在 webpack 打包過程中,經(jīng)常出現(xiàn) vendor.js, app.js 單個(gè)文件較大的情況,這偏偏又是網(wǎng)頁最先加載的文件,這就會(huì)使得加載時(shí)間過長,從而使得白屏?xí)r間過長,影響用戶體驗(yàn)。所以我們需要有合理的分包策略。
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>
我們把以下文件單獨(dú)抽離出來打包
- node_modules 文件夾下的,模塊
- 被 3 個(gè) 入口 chunk 共享的模塊
optimization.splitChunks
webpack 4 最大的改動(dòng)就是廢除了 CommonsChunkPlugin 引入了 optimization.splitChunks。如果你的 mode 是 production,那么 webpack4 就會(huì)自動(dòng)開啟 Code Splitting。
它內(nèi)置的代碼分割策略是這樣的:
新的 chunk 是否被共享或者是來自 node_modules 的模塊
新的 chunk 體積在壓縮之前是否大于 30kb
按需加載 chunk 的并發(fā)請求數(shù)量小于等于 5 個(gè)
頁面初始加載時(shí)的并發(fā)請求數(shù)量小于等于 3 個(gè)
雖然在 webpack4 會(huì)自動(dòng)開啟 Code Splitting,但是隨著項(xiàng)目工程的最大,這往往不能滿足我們的需求,我們需要再進(jìn)行個(gè)性化的優(yōu)化。
應(yīng)用實(shí)例
我們先找到一個(gè)優(yōu)化空間較大的項(xiàng)目來進(jìn)行操作。這是一個(gè)后臺管理系統(tǒng)項(xiàng)目,大部分內(nèi)容由 3-4 個(gè)前端開發(fā),平時(shí)開發(fā)周期較短,且大部分人沒有優(yōu)化意識,只是寫好業(yè)務(wù)代碼完成需求,日子一長,造成打包出來的文件較大,大大影響性能。
我們先用 webpack-bundle-analyzer 分析打包后的模塊依賴及文件大小,確定優(yōu)化的方向在哪。

看到這兩張圖的時(shí)候,我內(nèi)心是崩潰的,槽點(diǎn)如下
打包后生成多個(gè)將近 1M 的 js 文件,其中不乏 vendor.js 首頁必須加載的大文件
xlsx.js 這樣的插件沒必要使用,導(dǎo)出 excel 更好的方法應(yīng)該是后端返回文件流格式給前端處理
echart 和 iview 文件太大,應(yīng)該使用 cdn 引入的方法
吐槽完之后我們就要開始做正事了。正是因?yàn)橛羞@么多槽點(diǎn),我們才更好用來驗(yàn)證我們優(yōu)化方法的可行性。
抽離 echart 和 iview
由上面分析可知,echart 和 iview 文件太大,此時(shí)我們就用到 webpack4 的 optimization.splitChunks 進(jìn)行代碼分割了,把他們單獨(dú)抽離打包成文件。(為了更好地呈現(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>
此時(shí)我們再用 webpack-bundle-analyzer 分析一下

打包出來的 js 文件

從這里可以看出我們已經(jīng)成功把 echart 和 iview 單獨(dú)抽離出來了,同時(shí) vendor.js 也相應(yīng)地減小了體積。此外,我們還可以繼續(xù)抽離其他更多的第三方模塊。
CDN 方式
雖然第三方模塊是單獨(dú)抽離出來了,但是在首頁或者相應(yīng)路由加載時(shí)還是要加載這樣一個(gè)幾百 kb 的文件,還是不利于性能優(yōu)化的。這時(shí),我們可以用 CDN 的方式引入這樣插件或者 UI 組件庫。
- 在
index.html引入相應(yīng) 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', }}
- 刪除之前的引入方式并卸載相應(yīng) npm 依賴包
npm uninstall vue iview echarts xlsx --save
此時(shí)我們在來看一下打包后的情況

打包出來的 js 文件

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