Webpack 4.0 CommonsChunkPlugin 和 optimization splitChunks
該文章內容大致翻譯自webpack 4: Code Splitting, chunk graph and the splitChunks optimization
原有的問題
webpack 4.0 對程式碼模組的關係圖進行了一些巨大的優化,同時添加了一個新的optimization
用於模組的分離(可以看做是對CommonsChunkPlugin
的一次優化)。
先讓我們看看舊版關係圖的一些缺陷。
在之前的版本中,我們將各個模組打包進編譯後的檔案之中,同時這些檔案之間又是通過父子關係
來進行關聯,最後將我們整個專案中的所有模組串聯起來。
當其中一個檔案含有父級引用,那我們可以推斷出,在該檔案完成載入時,已經成功載入了父級檔案。那麼我們可以據此進行一些優化。比如當一個檔案中的模組已經在父級檔案中正常執行,那麼我們可以將該模組從檔案中移除,因為它必然已經被成功載入。
在入口點或非同步拆分點處引用這些檔案。這些檔案將會並行載入。
這種型別的關係圖使得分離splitting
變得非常困難。比如在你使用CommonsChunkPlugin
外掛時。會有一個或多個檔案內模組被移動到新的檔案中來。這一整個新檔案需要被新增到關係圖中來。但我們應該如何設定它的層級呢?作為舊有檔案的父級?還是子級?CommonsChunkPlugin
中將其設定為父級,但從技術層面來說,這是錯誤的,並且導致了一些負面的優化結果(提前載入的這個檔案中的部分模組不是必需的)。
現在新的關係圖中,引入了一個新概念:ChunkGroup
。包含檔案列表的檔案分組。
在入口點或非同步拆分點處我們會引用這個檔案分組,該分組內的檔案全都是並行載入。而一個檔案可以被多個檔案分組引用(但不會多次載入)。
現在不再使用父子級的關係來描述檔案之間的聯絡,取而代之的是檔案分組ChunkGroup
。
那麼此時,splitting
檔案就能夠被表述出來。被建立的新檔案可以被新增到所有包含原始檔案的檔案分組中。同時也不會因此產生負面優化效果。
CommonsChunkPlugin和SplitChunksPlugin的區別
這個問題被修復之後,我們可以更多的使用檔案拆分了。我們可以將任何檔案拆分出來並且不需要提高其載入優先順序。
CommonsChunkPlugin
存在以下這些問題:
- 需要下載當前還不需要使用的程式碼檔案。
- 非同步載入使用檔案效率低下。
- 很難使用。(猜測這裡指的是配置)
- 實現方式很難理解。
所以新的外掛誕生了:SplitChunksPlugin
。
它會使用模組引用計數和模組類別區分(比如:node_modules)來自動分離出需要被拆分的檔案內引用模組。
There is a paradigm shift here. TheCommonsChunkPlugin
was like: “Create this chunk and move all modules matchingminChunks
into the new chunk”. TheSplitChunksPlugin
is like: “Here are the heuristics, make sure you fullfil them”. (imperative vs declarative)
這裡沒有理解全部的內容。
SplitChunksPlugin
同時提供了更多的特性:
- 不會載入非必須檔案(除非進行了強制合併)
- 非同步檔案處理更有效率。
- 預設非同步處理檔案。
- 它將引用模組分散到多個庫檔案中。
- 更容易使用。
- 不依賴檔案引用關係圖。
- 更加的自動化。
例子
下面是一些使用SplitChunksPlugin
的例子。這些用例僅僅展現了它在預設配置下的行為。你也可以使用額外配置項來進行個性化定製。
提示:
-
可以通過
optimization.splitChunks
進行配置。這裡的例子是關於檔案的,預設情況下僅適用於非同步載入的檔案塊。但也可以新增optimization.splitChunks.chunks: "all"
來配置適用於所有型別的檔案。 -
我們假定每個額外匯入的庫檔案都大於30kb,因為優化僅在該體積之後開始進行。(可以通過配置
minSize
屬性進行修改,預設 30000)
Vendors
chunk-a chunk-b chunk-c chunk-d
webpack將會自動建立2個庫檔案:
-
vendors~chunk-a~chunk-b
: react, react-dom -
vendors~chunk-c~chunk-d
: angular -
chunk-a chunk-b chunk-c chunk-d
:僅 含有components
Vendors overlapping
chunk-a chunk-b chunk-c
webpack依然會建立2個庫檔案:
-
vendors~chunk-a~chunk-b~chunk-c
: react, react-dom -
vendors~chunk-b~chunk-c
: lodash -
chunk-a chunk-b chunk-c
:僅 含有components
Shared modules
chunk-a chunk-b chunk-c
假設所有的shared components
體積都大於 30kb,webpack將會建立一個庫檔案和一個通用元件檔案:
-
vendors~chunk-a~chunk-b~chunk-c
: vue -
commons~chunk-a~chunk-b~chunk-c
: some shared components -
chunk-a chunk-b chunk-c
:僅 含有components
當這些shared components
體積小於30kb是,webpack會故意將該模組複製到chunk-a chunk-b chunk-c
三個檔案中。我們認為進行分離所減小的載入體積的整體效果並不如一次額外的載入請求的消耗。
Multiple shared modules
chunk-a chunk-b chunk-c chunk-d
webpack將會建立2個庫檔案及2個通用元件檔案
vendors~chunk-a~chunk-b~chunk-c vendors~chunk-b~chunk-c~chunk-d commons~chunk-a~chunk-c commons~chunk-c~chunk-d
chunk-a chunk-b chunk-c chunk-d
: Only the components
提示:因為生成的匯入檔名稱包含所有的原始檔名稱,所以我們推薦在生產環境中使用的長效快取檔案不要包含[name]
在檔名中,或者設定optimization.splitChunks.name: false
來關閉檔名生成邏輯。這樣即使在後續開發中對該檔案添加了新的引用,也不會修改檔名,該快取邏輯依然生效。