We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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 开始,自带的 SplitChunksPlugin 替代了之前的 CommonsChunkPlugin 插件,对代码自动进行拆分(Code Split)的优化,并伴随一个默认的配置能满足大部分情况下的代码优化。
SplitChunksPlugin
CommonsChunkPlugin
继续之前先讨论一下 sync 与 async 类型的脚本。
<script>
import()
小贴士:这里顺便区分一下 bundle 与 chunk。前者是个更大的单位,可理解成根据 entry 配置生成的一个输出,而 chunk 可理解成从 bundle 中拆分出来的更小粒度代码形成的文件。本质上这个界定也没那么严格,或者解释也没有那么统一,只是可以这先么理解。
bundle
chunk
entry
SplitChunksPlugin 的默认配置:
module.exports = { //... optimization: { splitChunks: { chunks: "async", minSize: 30000, maxSize: 0, minChunks: 1, maxAsyncRequests: 5, maxInitialRequests: 3, automaticNameDelimiter: "~", name: true, cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, priority: -10 }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true } } } } };
默认配置下,会根据如下条件进行代码优化:
node_modules
在满足最后两个条件时,决定了 chunks 应越大越好,而不是越多。
这里主要讨论配置中的 chunks 配置项。它的可选值有
chunks
async
initial
all
function(chunk)
所以他们有什么区别,特别是 initial 方式,究竟会产生怎样的效果。这就是本文要探究的。
下面通过示例看看三者在对正常与动态加载的代码效果上有什么区别。示例借用自 Webpack 4 — Mysterious SplitChunks Plugin,有调整。通过 webpack-bundle-analyzer 查看编译输出的组成情况。
a.js
import "react"; import("lodash"); import "jquery"; console.log("a");
b.js
import("react"); import("lodash"); import "jquery"; console.log("b");
webpack.config.js
module.exports = { entry: { a: "./a.js", b: "./b.js" }, output: { filename: "[name].bundle.js" }, optimization: { splitChunks: { cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, + chunks: "async", priority: 1 } } } }, plugins: [new BundleAnalyzerPlugin()] };
准备了两个入口文件,都引入了三个 npm 库,jquery,react,lodash。
根据上面的配置,执行 npx webpack 先看 async 模式下的输出。
npx webpack
async 模式下的输出
initial 模式下的输出
initial 即原始的拆分,原则就是有共用的情况即发生拆分。动态引入的代码不受影响,它是无论如何都会走拆分逻辑的(毕竟你要动态引入嘛,不拆分成单独的文件怎么动态引入?!)。而对于同步引入的代码,如果有多处都在使用,则拆分出来共用。
从上面 initial 模式下我们似乎看出了问题,即 在 a 中同步引入在 b 中动态引入的 react,它其实可以被抽成文件供两者共用的,只是因为引入方式不同而没有这样做。
所以 all 这种模式下,就会智能地进行判断以解决这个问题。此时不关心引入的模块是动态方式还是同步方式,只要能正确判断这段代码确实可以安全地进行拆分共用,那就干吧。
需要注意的是这里需要设置 minSize 以使 react 能够正确被拆分,因为它小于 30k,在同步方式下,默认不会被拆分出来(联想文章开头提到的那些条件)。
minSize
react
cacheGroups: { vendor: { chunks: "all", test: /[\\/]node_modules[\\/]/, + minSize: 0, } }
all 模式下的输出
看起来似乎 all 是最好的模式,因为它最大限度地生成了复用的代码,Webpack 默认就走这个模式打包不就得了。
在开头的时候提到过一个原因为何默认情况下只优化 async 代码。所以,除了 all 之外的另外两个选项是有存在意义的。并且,具体的优化场景需要根据具体的需求而定,all 所产生的效果并非所有情况下都需要。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
Webpack SplitChunksPlugin 的三种模式
自 Webpack 4 开始,自带的
SplitChunksPlugin
替代了之前的CommonsChunkPlugin
插件,对代码自动进行拆分(Code Split)的优化,并伴随一个默认的配置能满足大部分情况下的代码优化。sync 与 asycn 脚本
继续之前先讨论一下 sync 与 async 类型的脚本。
<script>
标签进行加载的。如果有多个这样的脚本,需要按顺序写标签进行加载。import()
加载的脚本。小贴士:这里顺便区分一下
bundle
与chunk
。前者是个更大的单位,可理解成根据entry
配置生成的一个输出,而 chunk 可理解成从 bundle 中拆分出来的更小粒度代码形成的文件。本质上这个界定也没那么严格,或者解释也没有那么统一,只是可以这先么理解。默认配置
SplitChunksPlugin
的默认配置:默认配置下,会根据如下条件进行代码优化:
node_modules
或可被多个地方复用。在满足最后两个条件时,决定了 chunks 应越大越好,而不是越多。
chunks 配置项
这里主要讨论配置中的
chunks
配置项。它的可选值有async
: 只优化动态加载的代码,其他类型的代码正常打包。initial
: 针对原始 bundle 代码进行优化。all
: 针对所有代码进行优化。function(chunk)
自定义拆分函数,不讨论所以他们有什么区别,特别是 initial 方式,究竟会产生怎样的效果。这就是本文要探究的。
示例
下面通过示例看看三者在对正常与动态加载的代码效果上有什么区别。示例借用自 Webpack 4 — Mysterious SplitChunks Plugin,有调整。通过 webpack-bundle-analyzer 查看编译输出的组成情况。
a.js
b.js
webpack.config.js
module.exports = { entry: { a: "./a.js", b: "./b.js" }, output: { filename: "[name].bundle.js" }, optimization: { splitChunks: { cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, + chunks: "async", priority: 1 } } } }, plugins: [new BundleAnalyzerPlugin()] };
准备了两个入口文件,都引入了三个 npm 库,jquery,react,lodash。
async
根据上面的配置,执行
npx webpack
先看 async 模式下的输出。async 模式下的输出
initial
initial
模式下的输出initial
即原始的拆分,原则就是有共用的情况即发生拆分。动态引入的代码不受影响,它是无论如何都会走拆分逻辑的(毕竟你要动态引入嘛,不拆分成单独的文件怎么动态引入?!)。而对于同步引入的代码,如果有多处都在使用,则拆分出来共用。all
从上面
initial
模式下我们似乎看出了问题,即 在 a 中同步引入在 b 中动态引入的 react,它其实可以被抽成文件供两者共用的,只是因为引入方式不同而没有这样做。所以
all
这种模式下,就会智能地进行判断以解决这个问题。此时不关心引入的模块是动态方式还是同步方式,只要能正确判断这段代码确实可以安全地进行拆分共用,那就干吧。需要注意的是这里需要设置
minSize
以使react
能够正确被拆分,因为它小于 30k,在同步方式下,默认不会被拆分出来(联想文章开头提到的那些条件)。cacheGroups: { vendor: { chunks: "all", test: /[\\/]node_modules[\\/]/, + minSize: 0, } }
all
模式下的输出结论
看起来似乎
all
是最好的模式,因为它最大限度地生成了复用的代码,Webpack 默认就走这个模式打包不就得了。在开头的时候提到过一个原因为何默认情况下只优化
async
代码。所以,除了all
之外的另外两个选项是有存在意义的。并且,具体的优化场景需要根据具体的需求而定,all
所产生的效果并非所有情况下都需要。相关资源
The text was updated successfully, but these errors were encountered: