Webpack4.0 升級配置

lnyx發表於2018-07-30

本文首發於 dawei.lv

本文基於 webpack 4.8.1

吐槽

webpack 彪版本號的速度真是飛快,4.0 釋出沒多久上去看的時候才 4.1.*,現在已經刷到 4.8.1 了,給人一種“我版本號很高了,可以安心升級了”的感覺,然而坑依然很多...尤其是 API 文件,到處可見 3.0 的陳舊資訊。Code Splitting 章節點進去依然在講 CommonsChunkPlugin ,CommonsChunkPlugin 點進去提示去看 SplitChunksPlugin,看文件的時候經常會迷失自我,心累...好了,吐槽完畢,下面是正文。需要直接複製貼上的同學直接拉到最後~

4.0 與 3.0 的區別

mode

webpack4.0 新增了 mode 的概念, mode 可以為 developmentproductionnone

development 幫我們設定了 process.env.NODE_ENV=development,並新增了 NamedModulesPlugin 外掛。process.env.NODE_ENV=development 可以用來顯示一些在開發模式下才顯示的 debug 資訊,請注意這個 NODE_ENV 不能在 webpack.config.js 中使用,只能在你的原始檔中使用。想要在 webpack.config.js 中也生效,需要在 package.json 的 script 指令碼前新增 NODE_ENV=development,如 NODE_ENV=development webpack --config webpack.dev.jsNamedModulesPlugin 是在開啟 HMR 的時候使用的外掛。

// webpack.development.config.js
module.exports = {
+ mode: 'development'
- plugins: [
-   new webpack.NamedModulesPlugin(),
-   new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
- ]
}
複製程式碼

production 幫我們設定了 process.env.NODE_ENV=production,並新增了 UglifyJsPluginModuleConcatenationPluginNoEmitOnErrorsPlugin 等外掛,在設定了 sideEffects=false 之後可以實現未引用程式碼刪除的功能。

// webpack.production.config.js
module.exports = {
+  mode: 'production',
-  plugins: [
-    new UglifyJsPlugin(/* ... */),
-    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
-    new webpack.optimize.ModuleConcatenationPlugin(),
-    new webpack.NoEmitOnErrorsPlugin()
-  ]
}
複製程式碼

optimization

另一個區別在於引入了 optimization 的概念,optimization.minimizeroptimization.splitChunks 是需要我們關注的兩個配置。

optimization.minimizer 用於指定 webpack 使用哪個程式碼壓縮外掛,預設為 new webpack.optimize.UglifyJsPlugin,推薦更換為 UglifyJSPlugin

+const UglifyJSPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
  //...
  optimization: {
    minimizer: [
-     new webpack.optimize.UglifyJsPlugin({})
+     new UglifyJSPlugin({})
    ]
  }
}
複製程式碼

optimization.splitChunks 替代了 3.0 的 CommonsChunkPlugin,實現公共程式碼抽取。具體 API 參見SplitChunksPlugin。劃幾個重點,webpack 生成已經給大部分使用者提供了預設的設定,mode=production 就已經帶了這個優化,BUT!! 預設開啟的程式碼分割只對非同步載入的程式碼有效,也就是如果你是多個入口的配置,那麼你的 react、react-dom、react-router 等公共庫以及你的 common 程式碼都會被重複打包進多個入口裡。emmmmm,這叫什麼開箱即用嘛,還是我們自己動手吧。

首先,optimization.splitChunks.chunks 設定為 all,使得 async 非同步載入的程式碼和 initial 初始化的程式碼都會被抽取。optimization.splitChunks.cacheGroups 新增 commonsvendors (如下)。

module.exports = {
  optimization: {
    splitChunks: {
      chunks: "all",
      cacheGroups: {
        commons: {
          name: "commons",
          test: /src[\/]/,
          chunks: "initial",
          priority: 2,
          minChunks: 2
        },
        vendors: {
          name: "vendors",
          test: /node_modules/,
          chunks: "initial",
          priority: 10,
          minChunks: 2
        }
      }
    }
  }
};
複製程式碼

這裡的 name 指定你要抽取出來的 js 的檔名,test 欄位用來篩選你要匹配的程式碼,minChunks:2 表示程式碼被引用 2 次及以上就會被抽取出來,commons 實現抽取你的 src 資料夾下的公共程式碼,vendors 則用於抽取 node_modules 下的公共庫。下面我們需要把我們抽取出來的 commons.jsvendors.js 新增到 HtmlWebpackPlugin ,以實現打包出來的 html 檔案引用 commons.jsvendors.js

new HtmlWebpackPlugin({
    //...
-   chunks: 'index',
+   chunks: ['vendors', 'commons', 'index'],
})
複製程式碼

到筆者釋出文章為止,HtmlWebpackPlugin 還不支援新增動態名稱的 cacheGroups,無法將未明確指定 name 的 vendors~chunk-a~chunk-b.js 之類的 js 打包進程式碼中,不過可以看到相關的程式碼已經快要出來了。之後就可以實現更精細的程式碼分割打包了。

plugins

使用 mini-css-extract-plugin 替代 extract-text-webpack-plugin抽取 css 到單獨檔案中,使用 optimize-css-assets-webpack-plugin 對 css 進行壓縮處理。

optimize-css-assets-webpack-plugin 在使用的時候強烈推薦設定 isSafe = true,避免 z-index 被修改的問題

new OptimizeCSSAssetsPlugin({
  cssProcessorOptions: {
    isSafe: true
  }
});
複製程式碼

最後

webpack4-demo 是筆者整理的 webpack4.0 demo,詳細的 webpack 配置可以在這裡找到。

  1. 支援開發/生產模式
  2. 支援開發模式下 HMR
  3. 支援程式碼分割、程式碼混淆壓縮
  4. 支援未引用程式碼刪除
  5. 支援 less、autoprefixer
  6. 支援單/多入口
  7. 支援檢視打包各個模組佔用大小

相關文章