optimization.splitChunks
and optimization.runtimeChunk
)替代了CommonsChunkPlugin。本文介紹這兩個新選項的用法。預設值
預設情況下會做一些優化,對多數使用者都是合適的。
注意,預設值只會影響按需載入的塊,因為要修改初始(initial)塊會影響HTML中的script
標籤。如果你可以自己處理(比如根據入口配置生成script
標籤的時候),那可以對初始化也應用這些預設的優化:optimization.splitChunks.chunks: "all"
。
webpack根據如下條件自動拆分塊:
- 新塊可以共享或者模組來自
node_modules
資料夾 - 新塊會大於30kb(min+gz以前)
- 按需載入塊之時最大的並行請求數小於等於5
- 頁面初次載入時最大的並行請求數小於等於3
為盡力滿足後兩個條件,塊的體積可以更大。
下面看幾個例子。
例1
1 2 |
//entry,js import("./a"); |
1 2 3 |
//a.js import "react"; //... |
結果:會建立一個獨立的包含React的塊。在執行import
呼叫時,這個塊會隨著包含./a
的塊並行載入。
為什麼:
- 條件1:這個塊包含的模組來自
node_modules
- 條件2:react大於30kb
- 條件3:在執行
import
呼叫時,並行請求數是2 - 條件4:不影響頁面初次載入
為什麼應該這樣拆分?
react可能不會像應用程式碼那樣經常變更。把它挪到一個獨立的塊,瀏覽器就可以快取它(假設你使用了長期快取配置:chunkhash、records、Cache-Control)。
例2
1 2 3 |
entry.js import("./a"); import("./b"); |
1 2 3 4 |
//a.js import "./helpers"; //helpers有40kb //... |
1 2 3 4 5 |
//b.js import "./helpers"; import "./more-helpers"; //more-helper也有40kb //... |
結果:會建立一個獨立的包含./helpers
的塊。在執行import
呼叫時,這個塊會與原始的塊並行載入。
為什麼:
- 條件1:這個塊由兩個
import
呼叫共享 - 條件2:helpers大於30kb
- 條件3:在執行
import
呼叫時的並行請求數為2 - 條件4:不影響頁面初次載入
為什麼應該這樣拆分?
讓helpers程式碼保留在每個塊中意味著使用者要下載它兩次,而獨立出來以後,則只需下載一次。實際上這也是有代價的,因為會多一次請求。這也是為什麼有最小30kb的限制的原因。
With optimizations.splitChunks.chunks: "all"
the same would happend for initial chunks. Chunks can even be shared between entrypoints and on-demand loading.
配置
對於喜歡折騰的使用者,還有很多選項可供使用。
宣告:不要在沒有度量的情況下手工優化。預設值考慮了最佳實踐和Web效能。
快取組
這個選項將模組分配到快取組(cacheGroups
)。
預設是將node_modules
中的所有模組都分配到一個叫vendors
的快取組,將至少在2個塊中重複出現的模組分配到另一個叫default
的快取組。
一個模組可以被分配到多個快取組。這個優化通過priority
選項或構成較大塊的模組來優先選擇快取組。
條件
在滿足所有條件的情況下,來自相同塊和快取組的模組會構成一個新塊。
有4個選項可以用於配置條件:
minSize
(default: 30000) 塊的最小大小minChunks
(default: 1) 拆分前共享一個模組的最小塊數maxInitialRequests
(default 3) 一個入口最大並行請求數maxAsyncRequests
(default 5) 按需載入時最大行行請求數
命名
要控制拆分後新塊的名字,可以使用name
選項。
注意:如果給不同的塊指定了相同的名字,結果就是這些塊會被合併成一個。這樣配置可以把所有vendor
模組拆分為一個由所有入口點/拆分點共享的塊,但我不建議這樣用。因為這會導致下載的程式碼變多。
魔術值true
會自動根據塊和快取組的鍵選擇一個名字。另外,除給這個選項傳一個字串,也可以傳一個函式。
如果名字與入口點名字相同,則刪除入口點。
選擇塊
通過chunks
選項可以選擇塊,有3個值:"initial"
、"async"
和"all"
。分別用於選擇初始塊、按需載入的塊和所有塊。
reuseExistingChunk
選項用於配置在模組完全匹配時重用已有的塊,而不是建立新塊。
選擇塊可以針對每個快取組分別設定。
選擇模組
test
選項控制當前快取組選擇哪個模組。省略表示選擇所有模組。值可以是RegExp、字串或函式。
可以匹配絕對模組資源的路徑或塊名字。如果匹配的是塊名字,則會選擇該塊中的所有模組。
配置快取組
以下是預設配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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
、priority
和reuseExistingChunk
則只能在快取組層次上配置。
cacheGroups
是一個物件,其中鍵是快取組的鍵,而值是選項(這是全部): chunks
、 minSize
、minChunks
、maxAsyncRequests
、maxInitialRequests
, name
。
要禁用預設組,傳入false
:optimization.splitChunks.cacheGroups.default: false
。
這裡預設快取組(default
)的優先順序(priority
)是負數,以便任意自定義的快取組都優先順序(預設為0)都會更高。
以下是一些配置的例項:
1 2 3 4 5 6 7 8 9 |
splitChunks: { cacheGroups: { commons: { name: "commons", chunks: "initial", minChunks: 2 } } } |
這樣就建立了一個commons
塊,包含入口點共享的所有程式碼。
注意:這會導致使用者不必要地下載更多程式碼。
1 2 3 4 5 6 7 8 9 |
splitChunks: { cacheGroups: { commons: { test: /[\\/]node_modules[\\/] name: "vendors", chunks: "all" } } } |
這樣就建立了一個vendors
塊,包含整個應用中來自node_modules的所有程式碼。
注意:這會導致使用者不必要地下載更多程式碼。
optimization.runtimeChunk
optimization.runtimeChunk: true
會給每個入口檔案的輸出再新增一個塊,其中只包含執行時。