译:https://medium.com/dailyjs/we...
背景
代码分割是前端性能优化中十分常见的优化手段。
提到代码分割, 往往离不开webpack中的一项配置, 它就是 splitChunks
。
现在比较多的项目用的都是webpack4, webpack 4 舍弃了之前的 commonChunkPlugin
,增加了 SplitChunksPlugin
。
对于这个插件,它的 option 选项有:
initial
async
all
三个值。
对于这三个值, 哪怕是工作多年的老司机, 能记得清, 区分的清的恐怕不是很多。
我最近也在做性能优化, 通过简单的几行配置, 白屏时间就缩短了将近 600 ms
, 十分喜人。
before :
after:
Load 时长由2.3s 降低至1.57s, 还是不错的。
具体的分析过程以及优化方法我将在下一篇实战篇
中介绍。
回归正题,我们先了解一下基础原理。
正文部分翻译自Medium, 原文地址:
https://medium.com/dailyjs/we...
正文
这是我的一个粗略尝试,通过一个常见的例子来理解和帮助你使用 SplitChunksPlugin
选项。
作为早期的爱好者,我试图理解代码分割 (Code-Spliting) 背后的魔法。
文档说 splitChucnks 可以接受三个合法的值, 它们分别是:
initial
async
all
。
我有点困惑,更加提高了我的好奇心。
我深入研究了文档的 Github 历史记录和 WebpackOptions 概要,并发现:
“There are 3 values possible ”initial”, ”async” and ”all”. When configured the optimization only selects initial chunks, on-demand chunks or all chunks.” — Github History“Select chunks for determining shared modules (defaults to “async”, “initial” and “all” requires adding these chunks to the HTML) ”
— WebpackOptions Schema
这里的想法是有 a.js 和 b.js 两个入口文件
,然后引用相同的 node_modules
。
其中的一些 module 会被动态引入,用来检验代码分割(Code-Spliting)的行为
。
我们使用 Webpack Bundle Analyzer Plugin
来帮助我们理解我们的 node_modules 是如何被分割的。
a.js
:
只有 lodash 是动态引入的
b.js:
我选这样的配置的主要原因是为了理解当存在公共库时,Webpack 配置的表现是如何的:
- 在一个入口文件动态引入,另一个则不是 - React
- 在两个入口文件都动态引入 - lodash
- 在两个入口文件中都不动态引入 - jquery
我们将保持这些文件不变,并通过 chunks 的值来更改 webpack 的配置。
1. chunks : async
— Optimization over async module
打包之后的结构:
chunks: async
告诉 webpack:
”hey, webpack!我只关心动态导入的模块的优化。你可以保留非动态模块“
现在,让我们一步一步看看发生了什么:
webpack 会从 b.js 提取出 react,并移动到一个新文件,但保持 a.js 中的 react 不动。
这个优化只会作用到动态模块。
import('react') 声明会产生独立的文件
import 'react'
则不会。
webpack 从 a.js 中提取 lodash,并移动到一个新文件,该文件也被 b.js 引用了。
这里不会对 jquery 进行优化,尽管 a.js 和 b.js 都引用了。
2. chunks : initial
— Optimization over Sync Module
打包之后:
chunks: initial
告诉 webpack:
hey, webpack!我不关心动态引入的模块,你可以为每一个模块分别创建文件。但是,我希望将所有非动态引入的模块放在一个 bundle 中,尽管它们还需要引入其他的非动态引入的木块,我准备与其他文件共享和分块我的非动态导入模块。
现在,让我们一步一步看看发生了什么:
- a.js 中的 react 会被移动到
node_vendors~a.bundle.js
。 - b.js 中的 react 会被移动到
0.bundle.js
- a.js 和 b.js 中的
lodash
会被移动到1.bundle.js
。
为什么?
因为这是一个动态引入
的模块。
jquery
是一个非动态导入的公共模块,会移动到 node_vendorsab.bundle.js,被 a.js 和 b.js 共享
。
3. chunks : all
— Optimization over Async and Sync Module
打包之后:
chunks: all
告诉 webpack:
hey, webpack!我不关心这是一个动态还是非动态引入的模块。都对它们进行优化。但要确保......你足够聪明这样做。
现在,让我们一步一步看看发生了什么:
- react 在 a.js 中是非动态引入的模块,在 b.js 中是动态引入的。因此,它转到单个文件 0.bundle.js,它将由两者引用。
- lodash 在两个文件中都是动态引入的,所以它显然得到一个单独的文件1.bundle.js
- jquery 是非动态导入的,因此它转到公共共享模块 node_vendorsab.bundle.js,并将由两者引用。
由此可见, 选用不同的值, 将直接影响 webpack
的打包行为, 打来带来不同的结果。
今天在看这部分的文档, 发现有这样一句描述:
Providingall
can beparticularly powerful
, because it means that chunks can beshared
even between async and non-async chunks.
官方明示的简直不要太明显。
但如何选用不同的值,来实现最优效果呢?
这点我们将在下一篇详细分析。
今天这篇就先到这, 希望对大家有所帮助, 谢谢大家。
如果你觉得这篇内容对你挺有启发,可以:
- 点个「在看」,让更多的人也能看到这篇内容。
- 关注公众号「前端e进阶」,掌握前端面试重难点,公众号后台回复「加群」和小伙伴们畅聊技术。
更多精彩: