webpack 4: 代碼拆分、代碼塊關係圖及優化插件splitChunks

webpack4 對 chunk graph(代碼塊關係網格) 進行了一些重大改進並用新的優化策略實現了 chunk spliting(對CommonsChunkPlugin的一種改進)。vue

咱們看下老 chunk graph 的一些缺點。node

在老的 chunk graph 中,chunks 經過父子關係來鏈接且 chunks 包含了 moudles 的。react

當一個擁有父塊的 chunk 被加載時,就能夠肯定它至少有一個父級已經加載完了。優化策略就是使用了這個原理。即當 chunk 的父塊同時擁有同一個 module 時,這個 module 就能夠今後 chunk 移除,由於它在任何狀況下都已經可用了。webpack

入口點(entry)或異步拆分點(async import)引用了的 chunk 是並行加載的。web

這種關係使得實現「分割」 chunks 變得困難。例如使用 CommonsChunkPlugin 時就會發生這種狀況。一個或多個 chunks 模塊被移除並放進一個新的 chunk,這個 chunk 須要被鏈接到 chunk graph 中。但要怎麼作呢?當作老 chunk 的父塊?仍是子塊?CommonsChunkPlugin 把它做爲父塊,但這在技術上是錯誤的,會對其餘優化產生負面影響(父塊信息不許確)。緩存

新的 chunk graph 引入了一個新對象:ChunkGroupChunkGroup 包含了 Chunksdom

在一個入口點或異步拆分點引用了一個 ChunkGroup,這意味着此組包含的全部 Chunks 都是並行的。一個 Chunk 能夠被多個 CHunkGroups 引用。異步

Chunk 之間再也不存在父子關係,而存在於 ChunkGroups 之間的關係中。async

如今 Chunks 的「分割」能夠實現了。分割出的新 Chunks 被添加到全部包含原 ChunkChunkGroups,這不會對父子關係產生負面影響。優化


如今解決了這個問題,咱們能夠開始更多地使用 chunk 分割了。咱們能夠不冒破壞 chunk graph 的風險地拆分任何 chunk

CommonsChunkPlugin 還有許多問題:

  • 會致使下載多餘的無用代碼。
  • 在異步 chunks 上效率低。
  • 用起來繁瑣。
  • 實現難以理解。

全部新的插件誕生了:SplitChunksPlugin

它使用 module 重複次數和類別(即node_modules)做爲依據,實現自動識別應該怎樣拆分 chunks

這是一種範式轉移。CommonsChunkPlugin 就像是:「快給我加一個新的 chunck 而後把全部匹配 minChunks 規則的模塊移進去」。SplitChunksPlugin 則像是:「這裏有一份圖紙,想辦法實現它們」。(命令式 vs 聲明式)

SplitChunksPlugin 還有一些別的好特性:

  • 從不下載多餘的模塊(只要你不經過命名(name)強制(enforce)執行塊合併)
  • 異步 chunks 仍然高效
  • 默認狀況下,異步 chunks 就是打開的
  • 當有多個第三方類庫時,會自行拆分這些 chunks
  • 容易上手
  • chunk graph 不依賴 hacks 手段
  • 更自動化

這裏有一些 SpitChunksPlugin 能夠爲你作些什麼的例子。這些例子只展現默認行爲。自定義配置會有更多的結果。

注意: 你能夠經過 optimiztion.splitChunks 對其進行配置。例子中關於 chunks 的,默認狀況下只在異步塊(async chunks)中起做用,不過配置 optimiztion.splitChunks.chunks: "all" 可使直塊(initial chunks)也其做用。

注意:咱們假設這使用的全部第三方庫都超過30kb,由於優化只會大於此大小後發生。

Vendors

chunk-a: react, react-dom, 一些組件 chunk-b: react, react-dom, 一些其餘組件 chunk-c: angular, 一些組件 chunk-d: angular, 一些其餘組件

webpack會自動添加兩個 vendors chunks,像下面這樣:

vendors~chunk-a~chunk-b: react,react-dom vendors~chunk-c~chunk-d: angular chunk-achunk-d: 只有組件

交叉 Vendors

chunk-a: react, react-dom, 一些組件

chunk-b: react, react-dom,lodash, 一些其餘組件

chunk-c: react,react-dom.lodash 一些組件

一樣的,webpack會自動添加兩個 vendors chunks,像下面這樣:

vendors~chunk-a~chunk-b: react,react-dom

vendors~chunk-c~chunk-d: lodash

chunk-achunk-c: 只有組件

模塊共享

chunk-a: vue, 一些組件, 一些共享組件

chunk-b: vue, 一些其餘組件, 一些共享組件

chunk-c: vue, 一些組件, 一些共享組件

假設共享組件的大小大於30kb,webpack 會添加一個新 vendors chunk 和 一個 commons chunk, 就像這樣:

vendors~chunk-a~chunk-b~chunk-c: vue

commons~chunk-a~chunk-b~chunk-c: 一些共享組件

chunk-achunk-c: 只有組件

當共享組件大小小於30kb,webpack 會特地將chunk-a 中的模塊複製到 chunk-b 中,咱們認爲減小的下載大小不值得爲此單獨加載模塊而發起額外請求。

多個模塊共享

chunk-a: react, react-dom, 一些組件,一些共享的react組件

chunk-b: react, react-dom, angular, 一些其餘組件

chunk-c: react,react-dom,angular, 一些組件, 一些共享的react組件,一些共享的angular組件

chunk-d: angular, 一些其餘組件, 一些共享的angular組件

webpack 添加兩個 vendors chunks 和兩個 commons chunks

vendors~chunk-a~chunk-b~chunk-c: react,react-dom

vendors~chunk-b~chunk-c~chunk-d: angular

commons~chunk-a~chunk-c: 一些react共享組件

commons~chunk-c~chunk-d: 一些angular共享組件

chunk-achunk-d: 只有組件


注意:因爲 chunk 名稱由全部 chunk 來源名稱組合而成,所以建議在長期緩存的生成環境中,文件名應該含有[name],或者經過 optimization.splitChunks.anme:false 關閉建立名稱。不然在添加更多具備相同 vendorschunks 時,先前的文件會失效。

翻譯原文地址:webpack 4: Code Splitting, chunk graph and the splitChunks optimization | 做者:Tobias Koppers

相關文章
相關標籤/搜索