splitChunks探索(二)
为了搞明白 splitChunks
,前前后后花了好几天看文档/看视频/搜索别人博客
,做了各种实验.奈何相关的文档纯英文还有一些看着有点难理解的东西,多花了很久才算是搞明白.
下面介绍一下optimization
的option示例配置:
module.exports = {
optimization: {
splitChunks:{ // 下面展示的值都是默认值
chunks: 'async', // 'initial': 初始静态加载,'all': 所有, 'async': 按需加载
minSize: 30000, // 30000,大于这个值的文件会被提取成单独文件
// 被引用的次数,如果chunks为:
// 'initial',则判断通过静态加载 (import ... from ...) 和 require('....')等 的文件次数;如果chunks为
// 'async': 怎判断通过动态加载: import ('...') 的文件次数
// 'all': 计算 'initial' 和 'async '共同的次数
minChunks : 1,
maxInitialRequests: 3,
maxAsyncRequests: 5,
// 注意:查看webpack源码里 cacheGroups.chunks的默认值为 `initial`
// 但实测有点不一样,见下方: 一些注意点(个人总结)的第1点
cacheGroup: {
vendors: {
name: 'vendors',
chunks: 'initial',
maxInitialRequests: 3,
maxAsyncRequests: 5,
priority: -10,
reuseExistingChunk: true,
utomaticNameDelimiter: '.'
},
default: {
minChunks: 2,
priority: -20,
name: 'default',
minSize: 0,
}
}
},
runtimeChunk: {
name: entryPoint => `runtime-${entryPoint.name}`
}
}
}
重要说明(个人总结):
1 entry中每个入口点都会输出一个bundle文件
2 optimization.splitChunks.chunks的默认值为 "async",optimization.splitChunks.cacheGroup.chunks的默认值为"initial"
3 cacheGroups中的default分组是默认存在的,即使不进行任何配置
重要规则(个人总结):
1 chunks为"async"时,不会打包静态引用的文件.
"静态引用"
即"模块化引用"
,如:
ESModule:`import ... from ...`
CommonJs:`require('...')`
AMD:`...`
CMD:`...`
2 通过静态(模块化)方式引入的文件:
2.1 如果满足cacheGroups
中定义的某个分组的规则时,会被该分组捕获并提取
;
2.2 如果满足多个
分组规则时,会根据priority
(优先级,值越大优先级越高)被优先级高的分组捕获并提取
;
2.3 当都不满足cacheGroups
中自定义的其他分组时,如果满足default
分组规则,会被default
分组捕获并提取
;
2.4 如果也不满足default
分组的规则,这个文件就不会被提取
,而是会包含在它的引用文件打包生成的文件中
.
说明:
-
对于上面的
① 如果此文件2.4
,这是一个递归过程,进行静态引入的文件:不是入口(entry)文件
也会通过第(1)~第(3)点进行判断提取,如果可以被提取,那么它引用的文件会被包含在此文件的bundle中;
② 如果此文件是入口(entry)文件
,那么上面所说的不满足提取规则的文件会被包含在此入口文件生成的bundle文件中 -
这会有一个非常复杂多变的情况,需要多尝试各种情况,但核心的都离不开上面的
2.1~2.4
这4个规则
3 动态引入的文件总是会被提取出来,而不管chunks的值为什么
4 从入口点动态引入的文件也通过动态引入其他文件,被动态引入的文件会被单独提取出来
,这符合规则3
5 从入口点(如:entry.js
)动态引入的文件(如:common.js
)通过静态引用其他文件(如:lib.js
),那么common.js
被提取出来的文件里会包含这个lib.js
,同时的,如果这个lib.js满足cacheGroups里的其他规则,如:default
,那么lib.js
也会同时被提取到default内
.
一些注意点(个人总结)
1 chunks的值有3个:
'all'
,'async'
和'initial'
,
说明:
-
optimization.splitChunks.chunks
的默认值为'async'
; -
optimization.splitChunks.cacheGroups.chunks
的默认值为'initial'
,虽然源码里是这么写的,但是实际测试这个默认值应该是'async'
,不清楚是由optimization.splitChunks.chunks
继承而来的还是本身就是'async'
, -
如果发现配置的
cacheGroups
规则不起作用,很可能就是因为没有显示修改optimization.splitChunks.cacheGroups.chunks
的默认值; -
由于继承关系的存在,一般直接把
optimization.splitChunks.chunks
的值设置为'all'
2
optimization.splitChunks.cacheGroups
的属性可以继承optimization.splitChunks
的直接属性,但optimization.splitChunks.cacheGroups
的属性可以覆盖optimization.splitChunks
的直接属性
3
name
: 可以设置为true
,表示自动命名,但可能会出现common~app~...~shop~.js
这种恶魔一般的名称;可以直接设置为cacheGroups的key名称,如:name: 'common'
,会生成common~xxxx.js
名的bundle,xxxx
表示hash值
4
automaticNameDelimiter
: 生成的bundle文件名分隔符,默认为~
,生成的如:common~xxxx.js
,注意: 当name
的值不为true
时,默认使用.
作为分隔符,并且修改automaticNameDelimiter
不会生效
5
minChunks
: 最小被引用次数,当小于此值时,不会进行提取
6
minSize
: 文件大小,当小于此值时,不会进行提取
7
maxInitialRequests
: 入口并行加载的最大请求数.
个人理解为:静态引入文件的最大可提取数量,如果想要被提取的文件数量大于此值,会优先提取较大的文件,其他文件会包含在引用它的文件生成的bundle中.
参考自: 理解webpack4.splitChunks之maxInitialRequests
8
maxAsyncRequests
:按需加载时最大并行请求数量.
根据下面参考的博客:maxAsyncRequests
的值影响着request 次数和bundle大小
之间的关系.
参考自:webpack4 maxAsyncRequests记录
个人理解如下:
-
当实际按需加载的文件数量小于
maxAsyncRequests
的值时,会进行递归的server request
依赖的文件,是用request次数增加换取bundle变小
的方案; -
当实际按需加载的文件数量大于
maxAsyncRequests
的值时,会将依赖的文件合并成一个bundle,以此来减少server request
次数,是用bundle变大换取request次数减少
的方案; -
具体采用什么样的配置来优化项目,需要根据实际情况而定.
9
priority
: 分组规则优先级(cacheGroups特有
),当一个文件同时满足几个分组规则时,提取
操作由优先级高
的组来进行
10
reuseExistingChunk
: 是否对已提取的chunk进行复用(cacheGroups特有
)
11 重要: 实测发现
chunks/minChunks/minSize/maxInitialRequests
这几个规则,只要有一个不满足,就不会进行提取