跳到主要内容

splitChunks

2024年11月21日
柏拉文
越努力,越幸运

一、认识


Webpackoptimization.splitChunks 是一个功能强大的配置,用于对代码进行分割(Code Splitting),从而优化性能、减少文件体积和提高缓存利用率。splitChunks 优势如下:

  1. 减小主文件体积:将重复代码或第三方依赖抽离,避免多次打包。

  2. 按需加载:分离不常用的代码,只有在需要时才加载。

  3. 缓存优化:将变化较少的模块(如库文件)单独提取,提高缓存命中率。

  4. 加快构建速度:通过分离常用模块,减少每次构建时需要重新处理的代码量。

二、语法


splitChunks 的配置位于 optimization.splitChunks,可以全局设置,也可以针对不同类型的模块精细化配置。

optimization: {
splitChunks: {
chunks: 'async', // 默认只分割异步加载的代码
minSize: 20000, // 模块最小大小(字节)超过此值才会被分割
minRemainingSize: 0, // 保证剩余入口块的大小
minChunks: 1, // 最少引用次数,满足后才分割
maxAsyncRequests: 30, // 异步请求的最大并发数
maxInitialRequests: 30, // 入口文件的最大并发请求数
enforceSizeThreshold: 50000, // 强制分割的大小阈值
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/, // 匹配 node_modules
priority: -10, // 优先级低于自定义分组
reuseExistingChunk: true, // 复用已存在的块
},
react: {
name: 'react',
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
chunks: 'all',
priority: 30, // 高优先级
},
lodash: {
name: 'lodash',
test: /[\\/]node_modules[\\/](lodash)[\\/]/,
chunks: 'all',
priority: 25, // 次高优先级
},
vendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
priority: 10, // 最低优先级
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
}

三、配置项


3.1 chunks

chunks 定义分割的代码类型

  • async:仅分割动态导入的模块(默认)。

  • initial:仅分割初始加载模块。

  • all:分割所有模块(推荐,常用)。

语法

optimization: {
splitChunks: {
chunks: "all",
cacheGroups: {
lodash: {
name: "lodash",
test: /[\\/]node_modules[\\/]lodash[\\/]/,
chunks: "all",
},
vendors: {
chunks: "all",
name: "vendors",
test: /[\\/]node_modules[\\/]/,
},
common: {
chunks: "all",
name: "common",
test: /[\\/]src[\\/]common[\\/]/,
},
},
}
}

3.2 minSize

minSize 模块分割的最小大小(单位:字节)。模块小于这个值时,不会被分割。

语法

optimization: {
splitChunks: {
cacheGroups: {
common: {
minSize: 0,
name: "common",
test: /[\\/]src[\\/]common[\\/]/,
}
},
}
}

3.3 minChunks

minChunks 模块被引用的最少次数,满足这个条件的模块才会被分割。

3.4 cacheGroups

cacheGroups 定义分组规则,决定模块最终的归属和输出文件:

  • test:匹配的模块路径或名称(支持正则)。

  • name:输出文件的名称。

  • chunks: 定义分割的代码类型, ``async**:仅分割动态导入的模块(默认)。**initial**:仅分割初始加载模块。**all`:分割所有模块(推荐,常用)。

  • priority:优先级,数值越大优先级越高。

  • reuseExistingChunk:如果模块已经存在于某个分组中,其他分组引用时复用,而不是重新打包。如果关闭的话,每个分组都会重新生成模块副本,可能导致重复代码。建议:开启以减少重复代码。主要用于避免生成重复的 chunkreuseExistingChunk 用于检查是否已经存在可以复用的代码块。如果某些模块已经被打包到某个 chunk 中,则复用该 chunk,而不生成新的代码块。

splitChunks.cacheGroups 语法

optimization: {
splitChunks: {
chunks: "all",
cacheGroups: {
lodash: {
name: "lodash",
test: /[\\/]node_modules[\\/]lodash[\\/]/,
chunks: "all",
priority: 10,
},
vendors: {
chunks: "all",
priority: 9,
name: "vendors",
test: /[\\/]node_modules[\\/]/,
},
common: {
priority: 8,
minSize: 0,
chunks: "all",
name: "common",
test: /[\\/]src[\\/]common[\\/]/,
reuseExistingChunk: true,
},
},
},
}

splitChunks.cacheGroups 构建顺序: 在 WebpacksplitChunks.cacheGroups 配置中,最终的构建结果与规则的顺序和优先级有关。cacheGroups 是一个对象,其中的每个键定义了一个分组规则。Webpack 按照以下逻辑决定模块最终分配到哪个分组:

  1. priority 属性: 每个分组可以设置 priority,值越高,优先级越高。优先级高的分组会抢先匹配模块。如果模块符合多个分组规则,则分配给优先级最高的分组。

  2. 定义顺序(当 priority 相同): 如果没有明确指定 priority,则按定义顺序决定优先级,越早定义的分组优先匹配。

  3. 默认分组: 当模块未被任何分组匹配,或者所有分组的 test 条件都不满足时,模块会归入默认分组(如 defaultdefaultVendors)。

splitChunks.cacheGroups priority 决定归属:

cacheGroups: {
react: {
name: 'react',
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
chunks: 'all',
priority: 25,
},
vendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
priority: 10,
},
}

react 分组优先级高于 vendors(25 > 10),因此 reactreact-dom 模块会被优先提取到 react.js,即使它们也符合 vendors 分组规则。

splitChunks.cacheGroups 顺序影响默认行为: 如果没有设置 priorityWebpack 会按分组的定义顺序匹配:

cacheGroups: {
vendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
},
react: {
name: 'react',
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
chunks: 'all',
},
},

在这种情况下,reactreact-dom 会被 vendors 捕获,因为 vendors 规则定义在前。

splitChunks.cacheGroups 规则冲突时的分组分配: 当多个规则的优先级相同时, 模块会按最后一个规则匹配分组。如果模块被两次以上使用,默认会划分到最通用的分组。

3.5 maxAsyncRequests

maxAsyncRequests 限制异步模块内部并行加载的最大请求数, 也就是每个 import() 里面最大的请求数

3.6 maxInitialRequests

maxInitialRequests 限制初始并行加载的最大请求数 , 也就是说每个 import() 里面最大的请求数

3.7 enforceSizeThreshold

enforceSizeThreshold

3.8 automaticNameDelimiter

automaticNameDelimiter