webpack5 基本配置

這篇文件主要介紹以下基本配置:

  1. 拆分不同環(huán)境的配置文件:webpack-merge
  2. 自動(dòng)生成模板文件: html-webpack-plugin
  3. 自動(dòng)刪除以前的打包文件:clean-webpack-plugin
  4. 定義全局變量:
    • 使用cross-env設(shè)置命令行參數(shù),并在配置文件中獲取process.env.xxx,這個(gè)只能在腳本配置文件中獲取
    • 使用webpack.DefinePlugin設(shè)置模塊中可以使用的全局變量,注意要使用JSON.stringify封裝變量
  5. 開(kāi)發(fā)環(huán)境跨域設(shè)置:devServer.proxy中設(shè)置代理
  6. 樣式資源導(dǎo)入處理
    • css:css-loader, style-loader
    • less:less-loader
    • 增加瀏覽器兼容前綴:postcss-loaderautoprefixer插件結(jié)合使用
    • 抽離css文件:mini-css-extract-pluginloader和插件
  7. 圖片資源導(dǎo)入處理
    • file-loader:將資源文件抽離出來(lái),打包到指定位置
    • url-loader:同file-loader,但url-loader增加文件大小閾值,小于閾值使用base64導(dǎo)入
  8. 將es6轉(zhuǎn)換成es5:babel-loader

創(chuàng)建demo

  1. 創(chuàng)建項(xiàng)目
mkdir webpack-demo
cd webpack-demo
npm init -y
npm i webpack webpack-cli -D

可以看到package.json中webpack 和 webpack-cli的版本,現(xiàn)在最新的已經(jīng)是webpack5

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.40.0",
    "webpack-cli": "^4.7.2"
  }
}
  1. 創(chuàng)建基本目錄
  • src:資源目錄,隨便創(chuàng)建一個(gè)文件index.js,作為文件入口
// index.js
function hello() {
  console.log('hello')
}
hello()  // 注意要調(diào)用這個(gè)函數(shù),不然會(huì)被默認(rèn)tree-shaking掉
  • dist:創(chuàng)建打包輸出目錄
  • webpack.config.js:webpack默認(rèn)的基本配置文件
const path = require('path')

module.exports = {
  entry: path.join(__dirname, 'src', 'index.js'), // 單文件入口
  output: {
    filename: 'bundle.js',  // 輸出文件名
    path: path.join(__dirname, 'dist')  // 輸出目錄
  }
}
  • 改下package.json腳本命令
"scripts": {
    "build": "webpack"
  },
  1. 啟動(dòng)打包:npm run build
    會(huì)在dist/bundle.js打包出以下結(jié)果,可以看出來(lái)webpack5的tree-shaking已經(jīng)非常強(qiáng)大,無(wú)用的代碼不再被保留
console.log("hello");

區(qū)分 開(kāi)發(fā)環(huán)境dev 和 生產(chǎn)環(huán)境prod

在大項(xiàng)目中,我們往往需要根據(jù)不同的環(huán)境來(lái)進(jìn)行不同的配置,所以需要拆分webpack配置文件

  1. 創(chuàng)建一個(gè)config目錄,用來(lái)區(qū)分不同環(huán)境的配置文件:
    • webpack.common.js:用來(lái)配置公共的webpack配置
    • webpack.dev.js:用來(lái)配置開(kāi)發(fā)環(huán)境專有的webpack配置
    • webpack.prod.js:用來(lái)配置生產(chǎn)環(huán)境專有的webpack配置
  2. 在不同環(huán)境的配置文件中,使用webpack-merge中的merge來(lái)合并公共的webpack配置文件(webpack4中是通過(guò)smart來(lái)合并的)
    npm i webpack-merge -D
// webpack.common.js 公共的配置
const path = require('path')
const srcPath = path.join(__dirname, '..', 'src')

module.exports = {
  entry: path.join(srcPath, 'index')
}


// webpack.dev.js
const path = require('path')
const commonConfig = require('./webpack.common')
const {merge} = require('webpack-merge')
const devConfig = {
  mode: 'development', // 開(kāi)發(fā)環(huán)境
  output: {
    filename: 'bundle.js',  // 輸出文件名
    path: path.join(__dirname, '..', 'dist')  // 輸出目錄
  }
}
module.exports = merge(commonConfig, devConfig)


// webpack.prod.js

const path = require('path')
const commonConfig = require('./webpack.common.js')
const {merge} = require('webpack-merge')

const prodConfig = {
  mode: 'production', // 生產(chǎn)環(huán)境
  output: {
    filename: 'bundle.[chunkhash].js',  // 輸出文件名,一般要加上hash
    path: path.join(__dirname, '..', 'dist')  // 輸出目錄
  }
}

module.exports = merge(commonConfig, prodConfig)
  1. package.json腳本中區(qū)分不同環(huán)境的啟動(dòng)命令
    先要安裝:npm install webpack-dev-server -D
    PS:在webpack4中開(kāi)發(fā)環(huán)境使用的命令是webpack-dev-server --config config/webpack.dev.js,在webpack5后,改成了webpack server
"scripts": {
    "build": "webpack --config config/webpack.prod.js",
    "dev": "webpack server --config config/webpack.dev.js"
  },
  1. 運(yùn)行npm run build,打包
// dist/bundle.004799ddc36231aeaad8.js
console.log("hello");

html-webpack-plugin 自動(dòng)創(chuàng)建index.html文件

打包的js文件,需要我們有一個(gè)載體來(lái)查看結(jié)果,也就是我們一般說(shuō)的模板文件index.html

  • 手動(dòng)創(chuàng)建一個(gè)index.html(根目錄)文件
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script src="./dist/bundle.004799ddc36231aeaad8.js"></script>
</body>
</html>

使用瀏覽器打開(kāi),可以看到正常輸出的結(jié)果


dev

這個(gè)載體文件,不單單是開(kāi)發(fā)環(huán)境需要,生產(chǎn)環(huán)境也是需要的,但是生產(chǎn)環(huán)境我們往往會(huì)生成不同的hash值來(lái)防止資源緩存,所以每次生成的文件名都是不同的,手動(dòng)引入入口文件往往不太現(xiàn)實(shí),所以需要借助html-webpack-plugin插件來(lái)自動(dòng)生成項(xiàng)目中的html頁(yè)面,并實(shí)現(xiàn)自動(dòng)導(dǎo)入對(duì)應(yīng)腳本

  • html-webpack-plugin 自動(dòng)創(chuàng)建index.html文件
  1. 安裝: npm i html-webpack-plugin -D
  2. plugins中使用,因?yàn)槭枪玫?,所以?xiě)在webpack.common.js配置文件中:
// webpack.common.js 公共的配置
const path = require('path')
const srcPath = path.join(__dirname, '..', 'src')
const htmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: path.join(srcPath, 'index'),
  plugins: [
    new htmlWebpackPlugin({
      // 以根目錄中的index.html文件作為模板來(lái)自動(dòng)生成dist/index.html文件
      // 注意,這里是相對(duì)根目錄而言的,因?yàn)槟_本的上下文是在根目錄下
      template: 'index.html'  
      // inject: 'head', // 腳本注入的位置,可以是head, body,或者為 false默認(rèn)
      // 在這里還可以自定義參數(shù),在模板中,使用ejs方式 <%= htmlWebpackPlugin.options %>獲取自定義屬性
      title: 'webpack demo',
      // webpack5默認(rèn)開(kāi)啟壓縮屬性,webpack4要手動(dòng)設(shè)置
      // minify: {
      //   removeComments: true, // 刪除注釋
      //   collapseWhitespace: true  // 刪除空格
      // }
    })
  ]
}
  1. 刪除根目錄下index.html模板中手動(dòng)導(dǎo)入的語(yǔ)句,并接收自在htmlWebpackPlugin設(shè)置的自定義參數(shù)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
  <!-- 這是注釋 -->
</body>
</html>
  1. 執(zhí)行打包命令npm run build,可以看到dist目錄下生成了index.html
    a. 自動(dòng)導(dǎo)入了打包后的文件
    b. 顯示了自定義參數(shù)的title標(biāo)題
    c. 默認(rèn)開(kāi)啟了壓縮,刪除了注釋和空格
<!doctype html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>webpack demo</title><script defer="defer" src="bundle.e97c675afbdcfa8f531d.js"></script></head><body></body></html>

clean-html-plugin 刪除之前的打包文件

隨便修改下入口文件,發(fā)現(xiàn)打包新的文件時(shí),之前生成的打包文件每次都會(huì)存在,所以我們往往配合clean-html-plugin,在每次生成新的打包文件之前,會(huì)先刪除之前的打包文件

  1. 安裝 npm i clean-webpack-plugin -D
  2. webpack.common.js中配置
// webpack.common.js 公共的配置
const path = require('path')
const srcPath = path.join(__dirname, '..', 'src')
const htmlWebpackPlugin = require('html-webpack-plugin')
// webpack5寫(xiě)法
const {CleanWebpackPlugin} = require('clean-webpack-plugin')

module.exports = {
  entry: path.join(srcPath, 'index'),
  plugins: [
    new CleanWebpackPlugin(), // 清除之前的打包文件
    new htmlWebpackPlugin({
      // 以根目錄中的index.html文件作為模板來(lái)自動(dòng)生成dist/index.html文件
      // 注意,這里是相對(duì)根目錄而言的,因?yàn)槟_本的上下文是在根目錄下
      template: 'index.html'  
    })
  ]
}

PS:webpack4中導(dǎo)入插件的寫(xiě)法為const CleanWebpackPlugin = require('clean-webpack-plugin')

  1. 再次打包時(shí),就發(fā)現(xiàn)之前的包被清除了

定義全局變量

我們通常會(huì)有個(gè)配置文件,需要根據(jù)環(huán)境的不同,配置不同的接口地址,這時(shí)一般就會(huì)用到全局變量,webpack可以使用DefinePlugin插件來(lái)設(shè)置全局變量

我們一般在package.json文件運(yùn)行腳本中,會(huì)自定義一個(gè)環(huán)境變量NODE_ENV(,這個(gè)變量其實(shí)是自定義的,但前端約定俗成用這個(gè)變量名):

// mac電腦
"scripts": {
    "build": "NODE_ENV=prod webpack --config config/webpack.prod.js",
    "dev": "NODE_ENV=dev webpack server --config config/webpack.dev.js NODE_ENV=development"
  },
// windows電腦
"scripts": {
    "build": "set NODE_ENV=prod && webpack --config config/webpack.prod.js",
    "dev": "set NODE_ENV=dev && webpack server --config config/webpack.dev.js NODE_ENV=development"
  },

然后在其它腳本中,我們就可以通過(guò)process.env.NODE_ENV來(lái)獲取

為了寫(xiě)一個(gè)腳本配置,適配所有電腦,所以要安裝cross-env解決跨平臺(tái)問(wèn)題:
npm i cross-env -D,這樣,就可以只使用一個(gè)腳本:

"scripts": {
  "build": "cross-env NODE_ENV=prod webpack --config config/webpack.prod.js",
  "dev": "cross-env NODE_ENV=dev webpack server --config config/webpack.dev.js"
},

然后在webpack.common.js中,打印process.env.NODE_ENV可以獲取到腳本中的設(shè)置值,注意,這個(gè)process.env只有在配置文件中才能獲取到,在其它index.js中是獲取不到的,除非設(shè)置了全局變量

// webpack.common.js
 plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
    })
  ]

webpack4之后,上面這些操作,webpack都幫我們內(nèi)置了,所以可以在任何js文件中都能獲取到process.env.NODE_ENV的值,這個(gè)值對(duì)應(yīng)的是webpack配置文件中的mode值,即developmentproduction

這里主要是說(shuō)明怎么接收命令行的參數(shù),并在DefinePlugin設(shè)置全局變量的方法,方便我們?cè)谀K中使用,但注意的是,設(shè)置的對(duì)象需要使用JSON.stringify轉(zhuǎn)換,包括字符串(否則字符串會(huì)被識(shí)別成變量而報(bào)錯(cuò))

開(kāi)發(fā)環(huán)境啟動(dòng)和配置

之前配置了開(kāi)發(fā)環(huán)境腳本,但一直沒(méi)用,現(xiàn)在有了index.html模板文件和打包后的js文件,就可以使用npm run dev啟動(dòng)命令,根據(jù)提示打開(kāi)瀏覽器,訪問(wèn)http://localhost:8080/就可以查看結(jié)果了

dev啟動(dòng)

跨域配置

在開(kāi)發(fā)環(huán)境最常用的配置是處理跨域問(wèn)題,在webpack.dev.js中設(shè)置devServer,這點(diǎn)和webpack4是一樣的

// webpack.dev.js

const path = require('path')
const commonConfig = require('./webpack.common')
const {merge} = require('webpack-merge')
const devConfig = {
  mode: 'development', // 開(kāi)發(fā)環(huán)境
  output: {
    filename: 'bundle.js',  // 輸出文件名
    path: path.join(__dirname, '..', 'dist')  // 輸出目錄
  },
  devServer: {
    // 設(shè)置代理
    proxy: {
      // 將本地 /api/xxx 代理到 localhost:6666/api/xxx
      // '/api': 'http://localhost:3000',

      // 將本地 /api2/xxx 代理到 localhost:6666/xxx,通常用這個(gè),/api2僅作為代理轉(zhuǎn)發(fā)的標(biāo)識(shí)
      '/api2': {
          target: 'http://localhost:3000',
          changeOrigin: true,
          pathRewrite: {
              '/api2': ''
          }
      }
    }
  }
}

module.exports = merge(commonConfig, devConfig)

修改index.js文件,請(qǐng)求跨域的接口

function hello() {
  console.log('hello11')
}
fetch('/api2/data').then(res => {
  console.log(1111)
})
// 顯示跨域
fetch('http://localhost:3000/data').then(res => {
  console.log(2222)
})
hello()

寫(xiě)個(gè)簡(jiǎn)單的express服務(wù)器來(lái)測(cè)試:

const express = require('express')
const app = express()

app.listen(3000, () => {
  console.log('server is running in port: 3000');
})
app.get('/data', (req, res) => {
  console.log('11111')
  res.send('hello')
})

然后啟動(dòng)開(kāi)發(fā)環(huán)境:npm run dev

image.png

image.png

文件資源處理

.js文件中導(dǎo)入import './style/index.css'樣式文件,運(yùn)行,發(fā)現(xiàn)會(huì)報(bào)錯(cuò),這是因?yàn)閣ebpack默認(rèn)只認(rèn)識(shí)js文件,其它類型的文件都不識(shí)別。
要使webpack識(shí)別它們,必須引入對(duì)應(yīng)的loader去處理,將其轉(zhuǎn)換成js認(rèn)識(shí)的文件

1. 處理樣式文件

識(shí)別.css文件

  1. 安裝npm i css-loader style-loader -D
  2. webpack.common.js中配置module.rules規(guī)則:
    • css-loade:為了在js中使用import方式導(dǎo)入css文件
    • style-loader:將樣式寫(xiě)在html文件中head標(biāo)簽內(nèi)的<style>標(biāo)簽中
module.exports = {
  entry: path.join(srcPath, 'index'),
   module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
    ]
  },
  },

識(shí)別.less文件(sass、stylus同理)

要在.js中使用import './src/style/xxx.less'文件:

  1. 安裝npm i css-loader style-loader less-loader less -D
  2. 配置
    • less-loader:將.less文件轉(zhuǎn)譯成.css文件
module: {
    rules: [
      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      }
    ]
  },

自動(dòng)添加hack前綴

  1. 安裝npm i postcss-loader autoprefixer -D
  2. webpack.common.js中配置
module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader', 'postcss-loader']
      },
      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader','postcss-loader',  'less-loader']
      }
    ]
  },
  plugins: [
    require('autoprefixer')
  ]

CSS文件抽離

在生產(chǎn)環(huán)境中,我們往往不會(huì)將樣式文件給打包到html文件中,而是單獨(dú)抽離css文件

  1. 安裝:npm i mini-css-extract-plugin -D
  2. 在生產(chǎn)環(huán)境配置文件中webpack.prod.js配置,將前面的 style-loader換成mini-css-extract-pluginloader
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const prodConfig = {
  mode: 'production', // 生產(chǎn)環(huán)境
  output: {
    filename: 'bundle.[chunkhash].js',  // 輸出文件名,一般要加上hash
    path: path.join(__dirname, '..', 'dist')  // 輸出目錄
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']
      },
      {
        test: /\.less$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader']
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name]-[contenthash].css'
    })
  ]
}
  1. 打包npm run build
    css抽離

2. 圖片資源文件

想在.css中使用url導(dǎo)入圖片

body {
  background-color: yellow;
  opacity: 0.7;
  transform: rotate(45deg);
  background: url('../imgs/img002.jpg');
}

或者在.js中使用import導(dǎo)入圖片

import img from './imgs/img002.jpg'

需要借助file-loader或者url-loader,url-loaderfile-loader差不多,只不過(guò)增加了一個(gè)設(shè)置文件大小閾值,當(dāng)小于這個(gè)閾值時(shí),使用base64導(dǎo)入文件

  • 開(kāi)發(fā)環(huán)境
  1. 安裝:npm i file-loader -D
  2. 在開(kāi)發(fā)環(huán)境,因?yàn)椴挥每紤]壓縮問(wèn)題,所以webpack.dev.js可以配置file-loader
// 處理css樣式文件中的url圖片
      {
        test: /\.(jpg|png|jpeg|gif)$/,
        use: ['file-loader']
      }
  • 生產(chǎn)環(huán)境
  1. 安裝: npm i url-loader -D
  2. 在生產(chǎn)環(huán)境,可以使用url-loader設(shè)置小圖片使用base64方式寫(xiě)入
// 處理css樣式文件中的url圖片
{
        test: /\.(jpg|png|jpeg|gif)$/,
        use: {
          loader:'url-loader',
          options: {
            limit: 8192,    //限制 8kb 以下使用base64
            esMoudle: false,
            name: '[name]-[hash:8].[ext]',
            // 打包到/images目錄下
            outputPath: 'images'
          }
        }
        
      }

解析ES6+代碼

  • 安裝: npm i babel-loader @babel/core @babel/preset-env -D
  • 配置:
// webpack.common.js
  module: {
    rules: [
      {
        test: /\.js$/,
        use: ['babel-loader'], // 1. 開(kāi)啟緩存
        include: srcPath, // 2. 縮小適合范圍(寫(xiě)include或exclude)
        exclude: /node_modules/
        }
    ]
  }

// 根目錄創(chuàng)建,.babelrc
{
  "presets": ["@babel/preset-env"],  // 一般使用@babel/preset-env就夠了
  "plugins": []
}

// 如果是高版本的babel,比如v7.8.0 或更高版本的babel等
// .babelrc 換成根目錄創(chuàng)建 babel.config.json
{
  "presets": [
    [
      "@babel/env",
      {
        "targets": {
          "edge": "17",
          "firefox": "60",
          "chrome": "67",
          "safari": "11.1"
        },
        "useBuiltIns": "usage",
        "corejs": "3.6.5"
      }
    ]
  ]
}

總的來(lái)說(shuō),webpack5對(duì)比webpack4來(lái)說(shuō),改動(dòng)不算太多,還算是比較平穩(wěn)過(guò)渡,最后,借用網(wǎng)上一張圖,說(shuō)明webpack4升級(jí)webpack5的改動(dòng):

webpack5與webpack4差異.png

參考:
https://blog.csdn.net/xiaolinlife/article/details/107032533
https://www.imooc.com/article/287156#comment

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Webpack 在網(wǎng)頁(yè)中會(huì)引用哪些常見(jiàn)的靜態(tài)資源? JS .js .jsx .coffee .ts(Type...
    小K強(qiáng)閱讀 484評(píng)論 0 0
  • 1、組織項(xiàng)目結(jié)構(gòu)2、用npm init -y 命令初始化項(xiàng)目3、安裝你需要的模塊 npm install "" -...
    comepeng閱讀 505評(píng)論 0 0
  • 一、Webpack基本配置及使用 1、安裝本地Webpack 2、 Webpack可以0配置 打包工具 -> 輸出...
    HHHxxx_Hx閱讀 437評(píng)論 0 0
  • 1. 安裝webpack到全局 在構(gòu)建之前,我們來(lái)在本地文件新建一個(gè)存放項(xiàng)目的文件夾,比如叫demo1這個(gè)項(xiàng)目,然...
    CodeMT閱讀 656評(píng)論 0 3
  • webpack 中間可能會(huì)出現(xiàn)cnpm , npm ,yarn等三種安裝方式,其實(shí)最終安裝的結(jié)果都是一樣的,只是安...
    諾克斯1閱讀 373評(píng)論 0 0

友情鏈接更多精彩內(nèi)容