- Published on
Webpack 4 升級隨記
- Authors
- Name
- 米K朗基羅
- @kvzl_
Webpack 4 推出已經有幾個月的時間,標榜了更好的性能、零配置(更多預設值)等等各種提升,只是一直以來的配置也還算堪用,所以看到 Webpack 4 風光上市,第一時間並沒有很想跟進哈哈。
不過最近考慮到本人即將入伍,想儘早把負責的專案做一下清理,就順手把 Webpack 給升級了,殊不知退伍後已經變 Webpack 5 了(別
揪竟是改了什麼
根據官方文章,大致上是這幾點:
- 性能提升:而且還有進步空間!
- 零配置:應該說更多預設值了,而且會根據 Mode 有所不同。雖然專案複雜到不能不寫配置,但可以省掉一些選項也是不錯啦。
- 支援 WebAssembly:這是未來一大趨勢,
而且收了錢當然要好好做事。
是說網路上已經有很多 hen 棒的文章啦,所以這裡只會紀錄我有用到的部分,不會涵蓋所有 Webpack 4 升級內容,有興趣知道更多的同學可以參考文末的參考文獻 :innocent:
起手式
一切先上再說:
yarn add -D webpack@4 webpack-cli
接著來看看我改了哪些東西:
mode
原本覺得是個有點不起眼的改進,甚至都有點懶得寫了,但仔細想想其實頗重要的啊!
在 Webpack 4 以前,都是用 NODE_ENV
來控制不同環境要啟用哪些選項跟 Plugin,但現在 Webpack 會自動根據 mode
這個選項直接幫你套好各種優化,省了很多事啊~
我主要是透過 CLI 來指定 mode
:
# before
NODE_ENV=production webpack
# after
webpack --mode production
如果還是有需要在配置裡面取得 mode
,可以改用 function 傳回設定,像這樣:
module.exports = (env, argv) => {
const debug = argv.mode === 'development'
return {
// 你的配置
}
}
ModuleConcatenationPlugin
Scope Hoisting 是自 Webpack 3 開始提供的一項功能,可以有效減少 production 打包後的體積。以前可以透過內建的 ModuleConcatenationPlugin
來達成,現在直接變成選項 optimization.concatenateModules
了,而且預設 production 模式時自動打開,所以連設定都免了 ヾ(*´∀ ˋ*)ノ
// before
{
plugins: [new webpack.optimize.ModuleConcatenationPlugin()]
}
// after
{
optimization: {
// concatenateModules: true, // production mode 會自己打開
}
}
UglifyJsPlugin
只要把 optimization.minimize
打開,Webpack 就會幫你用 UglifyJs 處理了,一樣 production 模式自動打開,可以省略的。
如果想針對 UglifyJs 做設定,可以透過 optimization.minimizer
:
// before
{
plugins: [
new webpack.optimize.UglifyJsPlugin({
/* 各種設定 */
}),
]
}
// after
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
{
optimization: {
// minimize: true, // production mode 會自己打開
minimizer: [
new UglifyJsPlugin({
/* 各種設定 */
}),
]
}
}
DefinePlugin
取而代之的做法是透過 optimization.nodeEnv
來指定 process.env.NODE_ENV
,不過預設已經是參照 mode
值了,所以可以省略。
// before
{
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: debug ? '"development"' : '"production"',
},
}),
]
}
// after
{
optimization: {
// nodeEnv: debug ? 'development' : 'production', // 預設參照 mode,可省略
}
}
NoEmitOnErrorsPlugin
主要是用來阻止轉譯失敗的程式碼被打包進去,不過現在也變成選項了:
// before
{
plugins: [
new webpack.optimize.NoEmitOnErrorsPlugin(),
]
}
// after
{
optimization: {
noEmitOnErrors: true,
}
}
CommonsChunkPlugin
雖然好像是為了更好的支援 Code Splitting 才棄用 CommonsChunkPlugin,不過我最後還是採用和原本類似的拆分方式,基本上只是換個寫法而已:
// before
{
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.js',
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'commons',
filename: 'commons.js',
}),
]
}
// after
{
optimization: {
runtimeChunk: 'single',
splitChunks: {
name: 'commons',
chunks: 'all',
cacheGroups: {
vendor: {
test: /node_modules/,
name: 'vendor',
chunks: 'all',
enforce: true
}
}
},
}
}
這裡要提一下我現在在弄的其實不是 SPA,而是有多個 Entry 的多頁面網站,這也是為什麼我會寫上 optimization.runtimeChunk: 'single'
。
一開始不知道各個 Entry 會有各自的 Runtime,導致不同 Entry 共用的模組實際上被初始化超過一次,花了不少時間才發現 Webpack 文件有提到這件事 QQ。(以前好像是會被歸納到 Common chunks 裡面)
加上這個選項可以讓 Runtime 的部分獨立成一個 Entry,以避免各個 Entry 有各自的 Runtime。
vue-loader
因為專案本身有用到 Vue.js,搞定 Webpack 後發現 vue-loader
好像有點問題,不過幫 vue-loader
升級就沒事了:
yarn add -D vue-loader@latest
然後 Webpack 的部分需要額外引入 Plugin:
const VueLoaderPlugin = require('vue-loader/lib/plugin')
{
plugins: [
new VueLoaderPlugin(), // <-- 記得加這個
]
}
其他重大變更可以看看 vue-loader
的官方文件。
一些感想
對我來說這次改進主要在區分 production 和 development,也就是根據環境做優化的這件事變得更容易了。一直以來 Webpack 被大家詬病的就是他的配置地獄,對初學者來說真的有夠不友善(甚至根本就是惡意吧 XD),能夠有點改善真是太棒了~
當然支援 WebAssembly 也是很重要的一部分,只是這件事對我這個小小前端好像沒有太大影響 (|||゚ д ゚),不過這東西一直都在我的學習清單裡面,之後有機會再來詳述。
以上,大 guy 4 John。