Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

webpack 4: Code Splitting, chunk graph and the splitChunks optimization 翻译 #12

Open
791045873 opened this issue Feb 1, 2019 · 2 comments

Comments

@791045873
Copy link
Owner

791045873 commented Feb 1, 2019

前情提要

由于业务代码的webpack是2.0版本的,打包速度慢且一些配置项有问题,便想升级至webpack4。升级后打包速度仍旧很慢,猜测是chunk分割的配置项写的不够合理导致的。所以研究了一下网上的webpack4最佳实践。

以上的第二篇文章很不错,但是众成翻译上的译文质量极差,简直就是从google翻译copy的。故决定自己翻译一下。

翻译正文

第一部分

webpack4对chunk graph(译者:chunk graph指chunk之间的图谱关系)做出了一些巨大的优化,并且添加了新的用于chunk分割的配置项optimization(相对于CommonsChunkPlugin有一些提升)。

让我们先来看一看旧的chunk graph有哪些缺点。(译者:即旧的CommonsChunkPlugin插件的chunk分割机制生成的chunk graph有哪些缺点)

在旧的graph中,chunks之间以父子的关系互相连接,并且chunks包含modules。

当一个有着父级的chunk被完全加载的时候,我们可以假定至少有一个它的父级chunk已经被加载了。这个信息可以在优化中使用。即,当一个chunk内包含的module被所有的父级chunk使用时,就可以把它从chunk中移除,因为他在任何情况下都是可用的。(译者:这里的意思是,既然该module在父级chunk中被使用了,且子chunk加载完成时必有一个父级chunk已经加载,故无需在子级chunk中重复加载该module)

当一系列的chunk在入口文件或者异步加载的分割点被引用时,这些chunk都是并行加载的。

这个类型的图会比较难表达chunk的分割。(译者:原文为:These kind of graph makes it difficult to express “splitting” of chunks。此处翻译没有把握)。举个例子,以下情况发生在使用CommonsChunkPlugin时。来自于一个或多个chunk的modules会被移除,并且放入一个新的chunk。这个新chunk需要与chunk graph产生关联。但是,如何产生呢?作为旧chunk的父级chunk还是子级chunk?CommonsChunkPlugin将它指定为父级chunk。但是从技术上来讲是错的,并且对其他压缩有了负面的影响(父级的信息不够精确)。

新的chunk graph才用了一个新的对象:the ChunkGroup。一个ChunkGroup包含chunks。

在入口文件或者异步加载的分割点,一个单独的chunkGroup会被引用。这意味着chunkGroup中包含的所有chunk都会被并行加载。一个chunk可以被多个chunkGroup引用。

从此在chunks之间不再有父子关系,相反,这种关系如今存在于ChunkGroups之间。

如今,Chunks的分割可以被表达了。一个新chunk被添加到所有包含着起点chunk的ChunkGroup中。这不会对父级的关系造成负面影响。

第二部分

现在,随着该问题的解决,我们可以更多的使用chunk splitting。我们可以split任意chunk而不需冒着打破chunk graph的风险。
CommonsChunkPlugin有着以下问题:

  • 他会导致下载的代码多于所需代码
  • 对于异步chunk是低效的
  • 很难使用
  • 执行很难被理解

所以,一个新的plugin诞生了:SplitChunksPlugin
它通过启发式的module重复计数和module category(即,node_modules)自动识别需要被分割为chunk的modules。然后split 这些 chunks。

这是一种范式的转变。CommonsChunkPlugin就像是:“create一个chunk,然后移动所有的匹配minChunks的modules到这个新chunk中”。SplitChunksPlugin就像是:“这是启发式的,确保你填满他们。”(强制的vs陈述式的)

SplitChunksPlugin同样拥有一些很棒的特性。

  • 从不下载不需要的modules
  • 在异步模块上工作高效
  • 默认使用异步chunk
  • 它将vendor拆分为多个vendor chunks
  • 简单易用(译者:webpack就没有易用的东西)
  • 他不需要依赖chunk graph hacks
  • 更自动化

第三部分

这里有一些例子展示了SplitChunksPlugin会为你做什么。这些例子仅仅展示默认的行为。通过额外的配置可以拥有更多的特性。

Note:你可以配置optimization.splitChunks。这个例子展示了一些关于chunks的东西,在默认情况下,它仅仅对异步chunk生效,但是通过optimization.splitChunks.chunks: "all"的配置,初始的chunk也会被同样处理。

Note:我们假定所有的额外library都大于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 overlapping

  • 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

Shared modules

  • 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

假定被分享的components都大于30kb,webpack将会创建一个vendors chunk和一个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

当公用的components的大小小于30kb时,webpack故意复制这些modules到chunk-a、chunk-b、chunk-c中。我们认为不值得为了减少下载的大小而增加一个额外的请求去下载被分离出去的chunk。

Multiple shared modules

  • 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:由于chunk name包含在所有的初始chunk name中,推荐在生产环境需要使用长缓存打包时不要在文件名中包含[name],或者选择关掉name生成器,即optimization.splitChunks.name: false。其他的文件会被废弃,即当更多包含着相同vendors的chunk被添加时。

@791045873
Copy link
Owner Author

补充几个介绍SplitChunksPlugin的文章:
Webpack4之SplitChunksPlugin
COMMONSCHUNKPLUGIN VS SPLITCHUNKSPLUGIN

@791045873
Copy link
Owner Author

补充一点关于chunkGroup的个人理解:
我认为chunkGroup是一种虚拟的概念。在webpack的配置中并无chunkGroup的体现,只是在分割代码时,我们可以将一系列的chunk想象为一个group。这个group应该在webpack的源码里有对应体现,只是使用者无法察觉。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant