在 webpack 打包過程中,經常出現(xiàn) vendor.js, app.js 單個文件較大的情況,這偏偏又是網頁最先加載的文件,這就會使得加載時間過長,從而使得白屏時間過長,影響用戶體驗。所以我們需要有合理的分包策略。
CommonsChunkPlugin
在 Webapck4.x 版本之前,我們都是使用 CommonsChunkPlugin 去做分離
<pre data-language="javascript" id="L4z5I" class="ne-codeblock" style="border: 1px solid #e8e8e8; border-radius: 2px; background: #f9f9f9; padding: 16px; font-size: 13px; color: #595959">plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module, count) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(path.join(__dirname, './node_modules')) === 0
)
},
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
chunks: 'initial',
minChunks: 2,
}),
]</pre>
我們把以下文件單獨抽離出來打包
- node_modules 文件夾下的,模塊
- 被 3 個 入口 chunk 共享的模塊
optimization.splitChunks
webpack 4 最大的改動就是廢除了 CommonsChunkPlugin 引入了 optimization.splitChunks。如果你的 mode 是 production,那么 webpack4 就會自動開啟 Code Splitting。
它內置的代碼分割策略是這樣的:
新的 chunk 是否被共享或者是來自 node_modules 的模塊
新的 chunk 體積在壓縮之前是否大于 30kb
按需加載 chunk 的并發(fā)請求數量小于等于 5 個
頁面初始加載時的并發(fā)請求數量小于等于 3 個
雖然在 webpack4 會自動開啟 Code Splitting,但是隨著項目工程的最大,這往往不能滿足我們的需求,我們需要再進行個性化的優(yōu)化。
應用實例
我們先找到一個優(yōu)化空間較大的項目來進行操作。這是一個后臺管理系統(tǒng)項目,大部分內容由 3-4 個前端開發(fā),平時開發(fā)周期較短,且大部分人沒有優(yōu)化意識,只是寫好業(yè)務代碼完成需求,日子一長,造成打包出來的文件較大,大大影響性能。
我們先用 webpack-bundle-analyzer 分析打包后的模塊依賴及文件大小,確定優(yōu)化的方向在哪。

然后我們再看下打包出來的 js 文件

看到這兩張圖的時候,我內心是崩潰的,槽點如下
打包后生成多個將近 1M 的 js 文件,其中不乏 vendor.js 首頁必須加載的大文件
xlsx.js 這樣的插件沒必要使用,導出 excel 更好的方法應該是后端返回文件流格式給前端處理
echart 和 iview 文件太大,應該使用 cdn 引入的方法
吐槽完之后我們就要開始做正事了。正是因為有這么多槽點,我們才更好用來驗證我們優(yōu)化方法的可行性。
抽離 echart 和 iview
由上面分析可知,echart 和 iview 文件太大,此時我們就用到 webpack4 的 optimization.splitChunks 進行代碼分割了,把他們單獨抽離打包成文件。(為了更好地呈現(xiàn)優(yōu)化效果,我們先把 xlsx.js 去掉)
vue.config.js 修改如下:
<pre data-language="javascript" id="uP8eu" class="ne-codeblock" style="border: 1px solid #e8e8e8; border-radius: 2px; background: #f9f9f9; padding: 16px; font-size: 13px; color: #595959">chainWebpack: config => {
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
vendors: {
name: 'chunk-vendors',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial'
},
iview: {
name: 'chunk-iview',
priority: 20,
test: /[\\/]node_modules[\\/]_?iview(.*)/
},
echarts: {
name: 'chunk-echarts',
priority: 20,
test: /[\\/]node_modules[\\/]_?echarts(.*)/
},
commons: {
name: 'chunk-commons',
minChunks: 2,
priority: 5,
chunks: 'initial',
reuseExistingChunk: true
}
}
})
},
</pre>
此時我們再用 webpack-bundle-analyzer 分析一下
[圖片上傳中...(image-3a07ae-1626658031151-3)]
打包出來的 js 文件
[圖片上傳中...(image-a0cc41-1626658031151-2)]
從這里可以看出我們已經成功把 echart 和 iview 單獨抽離出來了,同時 vendor.js 也相應地減小了體積。此外,我們還可以繼續(xù)抽離其他更多的第三方模塊。
CDN 方式
雖然第三方模塊是單獨抽離出來了,但是在首頁或者相應路由加載時還是要加載這樣一個幾百 kb 的文件,還是不利于性能優(yōu)化的。這時,我們可以用 CDN 的方式引入這樣插件或者 UI 組件庫。
- 在
index.html引入相應 cdn 鏈接
<head> <link rel="stylesheet" /></head><body> <div id="app"></div> <script src="https://cdn.bootcss.com/vue/2.6.8/vue.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/iview/3.5.4/iview.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/xlsx/0.16.8/xlsx.mini.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/xlsx/0.16.8/cpexcel.min.js"></script></body>
-
vue.config.js配置externals
configureWebpack: (config) => { config.externals = { vue: 'Vue', xlsx: 'XLSX', iview: 'iView', iView: 'ViewUI', }}
- 刪除之前的引入方式并卸載相應 npm 依賴包
npm uninstall vue iview echarts xlsx --save
此時我們在來看一下打包后的情況

打包出來的 js 文件

well done ! 這時基本沒有打包出大文件了,首頁加載需要的 vendor.js 也只有幾十 kb,而且我們還可以進一步優(yōu)化,就是把 vue 全家桶的一些模塊再通過 cdn 的方法引入,比如 vue-router,vuex,axios 等。這時頁面特別是首頁加載的性能就得到大大地優(yōu)化了。