默認方式
webpack模式模式現在已經做了一些通用性優化,適用於多數使用者。
需要注意的是:默認模式只影響按需(on-demand)加載的代碼塊(chunk),因為改變初始代碼塊會影響聲明在HTML的script標簽。如果可以處理好這些(比如,從打包狀態里面讀取並動態生成script標簽到HTML),你可以通過設置optimization.splitChunks.chunks: "all",應用這些優化模式到初始代碼塊(initial chunk)。
webpack根據下述條件自動進行代碼塊分割:
- 新代碼塊可以被共享引用,OR這些模塊都是來自
node_modules文件夾里面 - 新代碼塊大於30kb(min+gziped之前的體積)
- 按需加載的代碼塊,最大數量應該小於或者等於5
- 初始加載的代碼塊,最大數量應該小於或等於3
為了滿足后面兩個條件,webpack有可能受限於包的最大數量值,生成的代碼體積往上增加。
我們來看一下一些例子:
Example 1
// entry.js import("./a"); // a.js import "react-dom"; // ...
結果:webpack會創建一個包含react-dom的分離代碼塊。當import調用時候,這個代碼塊就會與./a代碼被並行加載。
為什么會這樣打包:
- 條件1:這個代碼塊是從
node_modules來的 - 條件2:react-dom大於30kb
- 條件3:按需請求的數量是2(小於5)
- 條件4:不會影響初始代碼請求數量
這樣打包有什么好處呢?
對比起你的應用代碼,react-dom可能不會經常變動。通過將它分割至另外一個代碼塊,這個代碼塊可以被獨立緩存起來(假設你在用的是長期緩存策略:chunkhash,records,Cache-Control)
Example 2
// entry.js import("./a"); import("./b"); // a.js import "./helpers"; // helpers is 40kb in size // ... // b.js import "./helpers"; import "./more-helpers"; // more-helpers is also 40kb in size // ...
結果:webpack會創建一個包含./helpers的獨立代碼塊,其他模塊會依賴於它。在import被調用時候,這個代碼塊會跟原始的代碼並行加載(譯注:它會跟a.js和b.js並行加載)。
為什么會這樣打包:
- 條件1:這個代碼塊會被兩個導入(
import)調用依賴(指的是a.js和b.js) - 條件2:
helpers體積大於30kb - 條件3:按需請求的數量是2(小於5)
- 條件4:不會影響初始代碼請求數量
這樣打包有什么好處呢?
將helpers代碼放在每一個依賴的塊里,可能就意味着,用戶重復會下載它兩次。通過用一個獨立的代碼塊分割,它只需要被下載一次。實際上,這只是一種折衷方案,因為我們為此需要付出額外的一次請求的代價。這就是為什么默認webpack將最小代碼塊分割體積設置成30kb(譯注:太小體積的代碼塊被分割,可能還會因為額外的請求,拖慢加載性能)。
通過optimizations.splitChunks.chunks: "all",上面的策略也可以應用到初始代碼塊上(inital chunks)。代碼代碼塊也會被多個入口共享&按需加載(譯注:以往我們使用CommonsChunkPlugin最通常的目的)。
配置
如果想要更深入控制這個按需分塊的功能,這里提供很多選項來滿足你的需求。
Disclaimer:不要在沒有實踐測量的情況下,嘗試手動優化這些參數。默認模式是經過千挑萬選的,可以用於滿足最佳web性能的策略。
緩存組(Cache Group)
這項優化可以用於將模塊分配到對應的Cache group。
默認模式會將所有來自node_modules的模塊分配到一個叫vendors的緩存組;所有重復引用至少兩次的代碼,會被分配到default的緩存組。
一個模塊可以被分配到多個緩存組,優化策略會將模塊分配至跟高優先級別(priority)的緩存組,或者會分配至可以形成更大體積代碼塊的組里。
Conditions
在滿足下述所有條件時,那些從相同代碼塊和緩存組來的模塊,會形成一個新的代碼塊(譯注:比如,在滿足條件下,一個vendoer可能會被分割成兩個,以充分利用並行請求性能)。
有四個選項可以用於配置這些條件:
minSize(默認是30000):形成一個新代碼塊最小的體積minChunks(默認是1):在分割之前,這個代碼塊最小應該被引用的次數(譯注:保證代碼塊復用性,默認配置的策略是不需要多次引用也可以被分割)maxInitialRequests(默認是3):一個入口最大的並行請求數maxAsyncRequests(默認是5):按需加載時候最大的並行請求數。
Naming
要控制代碼塊的命名,可以用name參數來配置。
注意:當不同分割代碼塊被賦予相同名稱時候,他們會被合並在一起。這個可以用於在:比如將那些多個入口/分割點的共享模塊(vendor)合並在一起,不過不推薦這樣做。這可能會導致加載額外的代碼。
如果賦予一個神奇的值true,webpack會基於代碼塊和緩存組的key自動選擇一個名稱。除此之外,可以使用字符串或者函數作為參數值。
當一個名稱匹配到相應的入口名稱,這個入口會被移除。
Select chunks
通過chunks選項,可以配置控制webpack選擇哪些代碼塊用於分割(譯注:其他類型代碼塊按默認方式打包)。有3個可選的值:initial、async和all。webpack將會只對配置所對應的代碼塊應用這些策略。
reuseExistingChunk選項允許復用已經存在的代碼塊,而不是新建一個新的,需要在精確匹配到對應模塊時候才會生效。
這個選項可以在每個緩存組(Cache Group)里面做配置。
Select modules
test選項用於控制哪些模塊被這個緩存組匹配到。原封不動傳遞出去的話,它默認會選擇所有的模塊。可以傳遞的值類型:RegExp、String和Function
通過這個選項,可以通過絕對資源路徑(absolute modules resource path)或者代碼塊名稱(chunk names)來匹配對應模塊。當一個代碼塊名稱(chunk name)被匹配到,這個代碼塊的所有模塊都會被選中。
配置緩存組(Configurate cache group)
這是默認的配置:
splitChunks: { chunks: "async", minSize: 30000, minChunks: 1, maxAsyncRequests: 5, maxInitialRequests: 3, name: true, cacheGroups: { default: { minChunks: 2, priority: -20, reuseExistingChunk: true, }, vendors: { test: /[\\/]node_modules[\\/]/, priority: -10 } } }
默認來說,緩存組會繼承splitChunks的配置,但是test、priorty和reuseExistingChunk只能用於配置緩存組。
cacheGroups是一個對象,按上述介紹的鍵值對方式來配置即可,值代表對應的選項:
除此之外,所有上面列出的選擇都是可以用在緩存組里的:chunks, minSize, minChunks, maxAsyncRequests, maxInitialRequests, name。
可以通過optimization.splitChunks.cacheGroups.default: false禁用default緩存組。
default緩存組的優先級(priotity)是負數,因此所有自定義緩存組都可以有比它更高優先級(譯注:更高優先級的緩存組可以優先打包所選擇的模塊)(默認自定義緩存組優先級為0)
可以用一些例子來說明:
Example 1
splitChunks: { cacheGroups: { commons: { name: "commons", chunks: "initial", minChunks: 2 } } }
這會創建一個commons代碼塊,這個代碼塊包含所有被其他入口(entrypoints)共享的代碼。
注意:這可能會導致下載額外的代碼。
Example 2
splitChunks: { cacheGroups: { commons: { test: /[\\/]node_modules[\\/]/, name: "vendors", chunks: "all" } } }
這會創建一個名為vendors的代碼塊,它會包含整個應用所有來自node_modules的代碼。
注意:這可能會導致下載額外的代碼。
optimization.runtimeChunk
通過optimization.runtimeChunk: true選項,webpack會添加一個只包含運行時(runtime)額外代碼塊到每一個入口。(譯注:這個需要看場景使用,會導致每個入口都加載多一份運行時代碼)
