本文大約1500字,看完本文大概須要10分鐘,動手嘗試須要1小時,若有錯誤,請指正。vue
webpack4出了兩個月,發現你們包括我對splitChunk的使用都仍是在摸索階段。我也看了挺多別人的配置demo,都以爲不太滿意或者沒獲得太好的解惑,issue 下面的問題也沒什麼人回覆,只能本身操做了,順便記錄下來,若是你們有更好的,歡迎評論區留下地址。node
若是你對這些配置仍是不熟悉的話,一拉到底,看看文檔react
先總覽一下全部配置,後續會根據demo跑一遍常見的需求。webpack
optimization: {
splitChunks: {
chunks: "async", // 必須三選一: "initial" | "all"(推薦) | "async" (默認就是async)
minSize: 30000, // 最小尺寸,30000
minChunks: 1, // 最小 chunk ,默認1
maxAsyncRequests: 5, // 最大異步請求數, 默認5
maxInitialRequests : 3, // 最大初始化請求書,默認3
automaticNameDelimiter: '~',// 打包分隔符
name: function(){}, // 打包後的名稱,此選項可接收 function
cacheGroups:{ // 這裏開始設置緩存的 chunks
priority: 0, // 緩存組優先級
vendor: { // key 爲entry中定義的 入口名稱
chunks: "initial", // 必須三選一: "initial" | "all" | "async"(默認就是async)
test: /react|lodash/, // 正則規則驗證,若是符合就提取 chunk
name: "vendor", // 要緩存的 分隔出來的 chunk 名稱
minSize: 30000,
minChunks: 1,
enforce: true,
maxAsyncRequests: 5, // 最大異步請求數, 默認1
maxInitialRequests : 3, // 最大初始化請求書,默認1
reuseExistingChunk: true // 可設置是否重用該chunk
}
}
}
},
複製代碼
接下來看看第一個例子git
entry: {
pageA: "./pageA", // 引用utility1.js utility2.js
pageB: "./pageB", // 引用utility2.js utility3.js
pageC: "./pageC" // 引用utility2.js utility3.js
},
optimization: {
splitChunks: {
cacheGroups: {
commons: {
chunks: "initial",
minChunks: 2,
maxInitialRequests: 5, // The default limit is too small to showcase the effect
minSize: 0 // This is example is too small to create commons chunks
}
}
}
},
複製代碼
結果如圖,一切都很正常 commons~pageA~pageB~pageC.js 文件就是utility2.js commons~pageB~pageC.js,根據上述代碼,這裏的utility2被引用了三次,首先就被抽離了commons~pageA~pageB~pageC.js,而後utility3被引用了兩次就放到了commons~pageB~pageC.js,最後只剩下被引用一次的utility1.js,就直接放到了pageA.js裏面,若是這裏的utility1.js的也是兩次,他仍是會新建一個chunk放進去,而不是合併到commons~pageB~pageC.js,除非同入口引用纔會合併。github
mpageA.js pageB.js pageC.jsweb
這裏有個地方是須要優化一下的,就是pageA.js pageB.js pageC.js的代碼很少,可是打出來的包很大,確定是一些webpack的運行文件,直接加上 runtimeChunksegmentfault
runtimeChunk: "single"
// 等價於
runtimeChunk: {
name: "manifest"
}
複製代碼
如今就行了緩存
引用第三方模塊 pageA引用vue.js pageB引用react react-dombash
vendor: {
test: /node_modules/,
chunks: "initial",
name: "vendor",
priority: 10,
enforce: true
}
複製代碼
可是,這樣子的話,會把pageA pageB pageC全部的庫都打包到一塊兒vendor.js
假如我想拆分這個vendor.js爲pageA-vendor.js pageB-vendor.js怎麼辦,我試了好久,試出一個最簡單的辦法,去掉手動的vendor,讓插件自動處理。
splitChunks: {
chunks: "all",
cacheGroups: {
commons: {
chunks: "initial",
minChunks: 2,
maxInitialRequests: 5, // The default limit is too small to showcase the effect
minSize: 0 // This is example is too small to create commons chunks
}
}
},
複製代碼
後來,我把webpack mode改爲production後,發現無論用了,一樣的配置,在生產模式下,打包出來的東西有點匪夷所思,vendor-pageB.js被合併到了pageB.js裏面了。
後來我折騰了很久也分析不出來爲何,本身折騰出來一種方式,仍是老子手動來吧,自動化一邊去
commons: {
chunks: "initial",
minChunks: 2,
maxInitialRequests: 5, // The default limit is too small to showcase the effect
minSize: 0 // This is example is too small to create commons chunks
},
'vendor-pageA': {
test: /vue/, // 直接使用 test 來作路徑匹配
chunks: "initial",
name: "vendor-pageA",
enforce: true,
},
'vendor-pageB': {
test: /react/, // 直接使用 test 來作路徑匹配
chunks: "initial",
name: "vendor-pageB",
enforce: true,
},
複製代碼
成功打包出來了本身想要的東西。
動態引入你們應該都不陌生,就是你們所說的懶加載,直接在pageA和pageB頁面裏動態引入common-async.js,在這裏我先說說,splitChunk應該是能夠自動化處理相似commonChunk裏的async,child等狀況的。
import(/* webpackChunkName: "common-async.js" */"./common-async").then(common => {
console.log(common);
})
複製代碼
還不錯,成功打包出來了
這時候再試試,在這個common-async.js裏面在引入共同的代碼f.js,看看會不會重複打包
f.js成功的被抽離出來了,其餘文件也沒有被重複打包,挺好的。
上面的例子裏面配置了一個commons,這裏的name能夠本身設置,也能夠不設置,我是沒設置的,你能夠試試設置了是什麼樣子的,而後你就會明白這個name其實在某些狀況下仍是不設置的比較好。
commons: {
chunks: "initial",
minChunks: 2,
maxInitialRequests: 5, // The default limit is too small to showcase the effect
minSize: 0 ,
name: "commons"
},
複製代碼
可見,splitChunk在懶加載方面,自動化處理的挺不錯的,但在多頁面的配置(根據不一樣的頁面抽離不一樣的vendor)裏,他由於有本身的一套優化策略,每每會獲得不是咱們想要的輸出。這篇文章只是我初步的一些常識,我尚未深刻去看源碼,後續有空可能會補上splitChunk源碼分析,到時候就更清晰了