SpawN

webpack 4: Code Splitting, chunk graph and the splitChunks optimization

原文链接: medium.com

webpack 4对块图进行了一些重大改进,并增加了对 chunk 拆分的新优化(这是对 CommonsChunkPlugin 的一种改进)。

让我们看看之前的块图存在的缺点。

之前的块图通过父子关系连接到其他块,chunk 包含模块。

当一个块有父母时,可以假定在加载时至少有一个父母已经加载了。这些信息可以被优化步骤所使用。当 chunk 中的模块在所有父母中都使用时,就可以把这个模块提取出来,因为它在任何情况下都需要使用。

在入口或者异步分割点引用这些 chunk 。这些 chunk 是并行加载的。

这种图形很难理解 chunks 的分割。例如在使用 CommonChunkPlugin 的时候,从一个或多个 chunks 删除模块并放入一个新模块,这个新模块需要连接到块图中。但是应该怎么定位这个新模块?作为之前 chunk 的父母?作为孩子? 在 CommonChunkPlugin 中将其添加为父母,但是从技术角度上这是错误的,也会造成对优化产生很多负作用。

新的块图引入了一个新对象:ChunkGroup. 一个ChunkGroup包含一个Chunks.

在入口点或异步分割点处引用一个ChunkGroup,这就意味着包含所有并行的Chunks。一个Chunk可以被引用在多个ChunkGroup中。

Chunk之间不再存在父子关系,ChunkGroups 之间也不存在这种关系。

现在 Chunks 的分割可以被理解了,因为新的Chunks被添加到所有包含原始 ChunkChunkGroups 中,这并不会影响父母关系。


现在解决了这个问题,我们可以开始更多的使用Chunk分割。我们可以拆分任何 chunk,而不用担心破坏块图。 CommonsChunkPlugin存在很多问题:

  • 它可能导致下载更多的超过我们使用的代码
  • 它在异步chunks中是低效的。
  • 配置繁琐,很难使用
  • 难以被理解

所以一个新的插件诞生了: SplitChunksPlugin

它使用模块重复计数和模块类别(如 node_modules ),通过 heuristics 自动识别应该被分块的模块,并分割 chunks

这有个两者的比喻,CommonsChunkPlugin就好像: 创建一个所有模块中都共同存在的模块。 而SplitChunksPlugin就像是:“Here are the heuristics, make sure you fullfil them”

SplitChunksPlugin 也有着不错的特点:

  • 不会下载不需要的代码
  • 对异步chunks也很高效
  • 被默认用于异步chunks
  • 可以通过多个vendor chunks来进行vender的分割
  • 使用简单
  • 不依赖块图
  • 基本上是自动的

这里有一些SplitChunksPlugin会为你做的例子。这些示例仅显示默认行为。有更多的可能性与额外的配置。

您可以通过optimization.splitChunks进行配置。这些示例提到了有关块的内容,默认情况下,它仅适用于异步块,但对于optimization.splitChunks.chunks:“all”对于初始块也是如此。

我们假设这里使用的每个外部库都大于30kb,因为优化仅在该阈值之后进行。

Vendors

chunk-a: react, react-dom, some components

chunk-b: react, react-dom, some other components

chunk-c: angular, some components

chunk-d: angular, some other components

webpack 会自动创建两个 vendors chunks, 结果如下:

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

vendors~chunk-c~chunk-d: angular

chunk-a to chunk-d: Only the components

Vendors 重叠

chunk-a: react, react-dom, some components

chunk-b: react, react-dom, lodash, some other components

chunk-c: react, react-dom, lodash, some components

webpack 会自动创建两个 vendors chunks, 结果如下:

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

vendors~chunk-b~chunk-c: lodash

chunk-a to chunk-c: Only the components

共享模块

chunk-a: vue, some components, some shared components

chunk-b: vue, some other components, some shared components

chunk-c: vue, some more components, some shared components

假设共享组件的大小大于30kb,webpack将创建vendors chunk 和一个a commons chunk,结果如下:

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

commons~chunk-a~chunk-b~chunk-c: some shared components

chunk-a to chunk-c: Only the components

When the size of the shared components is smaller than 30kb, webpack intentionally duplicates the modules in chunk-a to chunk-c. We think reduces download size is not worth the extra request needed for a separate chunk load.

多个共享模块

chunk-a: react, react-dom, some components, some shared react components

chunk-b: react, react-dom, angular, some other components

chunk-c: react, react-dom, angular, some components, some shared react components, some shared angular components

chunk-d: angular, some other components, some shared angular components 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: some shared react components

commons~chunk-c~chunk-d: some shared angular components

chunk-a to chunk-d: Only the components


Note: Since the chunk name includes all origin chunk names it’s recommended for production builds with long term caching to NOT include [name] in the filenames, or switch off name generation via optimization.splitChunks.name: false. Elsewise files will invalidate i. e. when more chunks with the same vendors are added.

由于块名称包含所有源块名称,因此建议在生产环境下使用来达到长期缓存,以避免在文件名中包含[name].或者通过optimization.splitChunks.name关闭名称生成:false。其他文件将使我无效。即当添加更多与同一vendors的块时。

via: https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366

作者: 选题者: @SpawN 译者: SpawN 校对: 校对者ID

本文由 LCTT 原创编译,Linux中国 荣誉推出