SplitChunksPlugin是webpack4中官方plugin,用於做分包打包的,可以幫你把重複引入的模塊按規則打包到指定的js裏面。以下是SplitChunksPlugin的默認配置:
splitChunks: {
chunks: "async", //在默認情況下,SplitChunksPlugin 僅僅影響按需加載的代碼塊,如果需要對同步的代碼做代碼分割打包,那麼chunk配置爲'all'
minSize: 30000, // 模塊的最小體積
minChunks: 1, // 模塊的最小被引用次數
maxAsyncRequests: 5, // 按需加載的最大並行請求數
maxInitialRequests: 3, // 一個入口最大並行請求數
automaticNameDelimiter: '~', // 文件名的連接符
name: true,
cacheGroups: { // 緩存組
vendors: { //引入的node modules裏面的庫打包成一個vendor
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: { //其他重複的模塊,如業務組件、自定義公共組件等
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
在單一入口頁的項目開啓splitChunk的功能其實配置很簡單,只需要在 optimization 裏面配置如下,splitChunk會使用默認的配置對項目進行拆包
splitChunks: {
chunks: 'all',
name: true
}
一般我們配置多入口頁,都會使用 HtmlWebpackPlugin ,如果是 HtmlWebpackPlugin 結合SplitChunkPlugin 使用的話,需要在不同的入口頁面指明該頁面對應的chunk的名稱,否則該頁面引用的chunk文件對應不上的話,頁面是無法正常加載的
下圖是我的項目結構,app.js是主入口頁,其他幾個入口頁都是分享出去的頁面,對應app.js裏面的一些模塊(app.js裏面的模塊採取異步加載的方式引入)
如果不使用 SplitChunksPlugin ,我們利用 BundleAnalyzerPlugin 打包分析工具查看打包後的結果(下圖),非常大,很多公共的庫或業務組件被重複打包
接着,我們按SplitChunksPlugin的基礎配置,在webpack.config.js裏面引入,以~連接的chunk就是SplitChunksPlugin使用基礎的配置給我們拆包出來的文件,這時我們的頁面是不能正常加載的,因爲這些拆包出來的chunk不能自動地注入到所引用的入口頁裏
那麼我們先把項目裏引用的node_modules的三方庫拆出來,並在入口文件中注入,SplitChunksPlugin配置如下:
splitChunks: {
chunks: 'all',
name: true,
cacheGroups: {
vendors: { // 項目基本框架等
chunks: 'all',
test: /node_modules/,
priority: 100,
name: 'vendors',
}
}
}
HtmlWebpackPlugin配置:
new HtmlWebpackPlugin({
template: './templete/index.html',
filename: 'index.html',
chunks: ['app', 'vendors'] //注入對應的入口js文件、拆包出來的verdor文件(命名跟SplitChunks cacheGroup裏配置的名稱一致)
}),
new HtmlWebpackPlugin({
template: './templete/index-no-pb.html',
filename: 'home.html',
chunks: ['home', 'vendors']
}),
new HtmlWebpackPlugin({
template: './templete/index-no-pb.html',
filename: 'profile.html',
chunks: ['profile', 'vendors']
}),
...
我們可以看到,除了公共庫的chunk,webpack還幫我們打包出了一些其他的公共chunk,這是因爲默認配置裏還有個default參數,會幫我們打包一些別的重複引用的模塊。同樣,我們還是需要給這些打包的chunk配置一下,不然這些公共chunk也不能被正常地注入
修改一下SplitChunksPlugin的配置
splitChunks: {
chunks: 'all',
name: true,
cacheGroups: {
vendors: { // 項目引用的三方庫,如mobx等
chunks: 'all',
test: /node_modules/,
priority: 100, //值越大,打包越優先參照此配置項
name: 'vendors',
},
commons: { // 其他同步加載公共包,如自定義組件等
chunks: 'all',
minChunks: 2,
priority: 80,
name: 'commons'
}
}
}
重寫了splitChunks 的 cacheGroups 默認參數後,可以按照我們的要求進行打包了,node_modules裏面的部分打包到vendor.chunk裏面,自定義的組件等其他重複引用模塊被打包到了commons.chunk裏,注意在HtmlWebpackPlugin 裏面也要同時配置commons這個chunk
其實,按上面的配置,我們的打包結果已經比之前優化很多了,但是,這並不是最好的處理結果。因爲commons.chunk裏面打包的重複模塊,在不同的入口頁其實是用不上的。commons.chunk打包了所有引用超過兩次的模塊,其中就包括record chunk、profile chunk、home chunk、rank chunk等,因爲這些部分同時在app.js和對應的入口頁中引用了。比如說我只打開profile.html入口頁,那我只需要profile chunk,而不需要另外的一些模塊。那我們再修改一下配置
splitChunks: {
chunks: 'all',
name: true,
cacheGroups: {
vendors: { // 項目引用的三方庫,如mobx等
chunks: 'all',
test: /node_modules/,
priority: 100,
name: 'vendors',
},
commons: { // 其他同步加載公共包,如自定義組件等
chunks: 'all',
minChunks: 3, //最小引用次數修改爲3,那麼app.js和其他入口頁共用的模塊就不會被打包進來,而是隻打包了引用次數超過三次的一些自定義組件
name: 'commons',
priority: 80,
},
default: false //注意把cacheGroups的默認的default設置爲false,不然還是會走default裏面的配置,將引用了兩次以上的模塊進行打包
}
}
最後結果如下圖所示,公共包有兩個,而業務邏輯模塊(home|rank|record|profile)沒有被打進commons.chunk裏面,被單獨打成了一個個異步chunk。
雖然最後的打包方式整體大小會比之前的稍大一點,但是在請求不同的入口頁時,會按需引入,以record.js入口頁爲例,請求時加載vendor + commons + record + recordChunk(約等於930多k),但是按之前的方式全部打到一個commons.chunk裏,請求時加載vendor + commons + record(約等於1019多k)
SplitChunksPlugin雖然好用,但是也不要盲目地使用,應該根據項目的具體情況而定,一般如果是單入口頁面,就直接按默認配置即可;多入口頁的話,可以根據具體情況再進行拆包,自己寫cacheGroups的配置的時候注意要關閉或者覆蓋默認配置。
【參考】
https://webpack.js.org/plugins/split-chunks-plugin/#defaults