# Code Split 代码分割
- webpack 代码分离 https://www.webpackjs.com/guides/code-splitting/
- SplitChunksPlugin 的默认行为 https://www.webpackjs.com/plugins/split-chunks-plugin/#optimizationsplitchunks
- webpack 打包优化 - splitChunks---CSDN--你才是向阳花 (opens new window)
代码分离是 webpack 中最引人注目的特性之一。此特性能够把代码分离到不同的 bundle 中,然后便能按需加载或并行加载这些文件。代码分离可以用于获取更小的 bundle、控制资源加载优先级,如果使用合理,会极大减小加载时间。--- 官网原话 -- 废话
代码分割(Code Split)主要做了:
分割文件:将打包生成的文件进行分割,生成多个 js 文件
防止重复: 如果多入口文件中都引用了同一份代码,我们不希望这份代码被打包到两个文件中,导致代码重复体积更大
按需加载:需要哪个文件就加载哪个文件。(有点抽象:主要是体现在网络请求上,比如:大概是点击按钮,通过 script 标签加载需要的 JS 文件,按需的 JS 文件应该会被处理成 script 标签以便引入,以上均为猜测)
# 使用
通过内置的 optimization.splitChunks
属性进行配置
SplitChunks
: 简单的来说就是 Webpack 中一个提取或分离代码的插件,主要作用是提取公共代码,防止代码被重复打包,拆分过大的 js 文件,合并零散的 js 文件,就是 CodeSplit 的具体配置和实现方式
先了解几个概念 - module、bundle、chunk 都是什么?
module
:模块,在 webpack 中任何文件都可以作为一个模块,借用官网的图片,左侧的这些类型文件,都可以认为是一个模块,只是需要配置不同的 loader,将文件转换成 webpack 可以支持打包的文件。
chunk
:编译完成准备输出时,webpack 将 module 按特定规则组成的一个个 chunk
bundle
:webpack 处理好 chunk 文件后,生成运行在浏览器中的代码
# 官方默认配置
module.exports = {
//...
optimization: {
splitChunks: {
// [initial(初始块)、async(按需加载块)、all(全部块)], 默认只对异步模块分割
chunks: "async",
// 公共配置属性--以下是默认值
minSize: 20000, // 分割代码最小的大小
minRemainingSize: 0, // 类似于minSize,最后确保提取的文件大小不能为0
minChunks: 1, // 至少被引用的次数,满足条件才会代码分割
maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
maxInitialRequests: 30, // 入口js文件最大并行请求数量
enforceSizeThreshold: 50000, // 超过50kb一定会单独打包(此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)
// 单独组,哪些模块要打包到一个组 , 以上的属性都会被单独的 cacheGroups 属性设置继承,但是优先级最低
cacheGroups: {
// 组名--chunk名
defaultVendors: {
test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
priority: -10, // 权重(越大越高)
reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
},
default: {
minChunks: 2, // 这里的minChunks权重更大
priority: -20,
reuseExistingChunk: true,
},
},
},
},
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 极简版
- 可以直接使用,其他配置就是默认的,想定制看下面 默认配置注解版
module.exports = {
// ...其他配置
optimization: {
// 代码分割配置
splitChunks: {
chunks: "all", // 对所有模块都进行分割、[initial(初始块)、async(按需加载块)、all(全部块)]
},
},
};
2
3
4
5
6
7
8
9
# 默认配置注解版
- 可以直接使用,配置就是默认的,也可以自行更改
module.exports = {
// ...其他配置
optimization: {
// 代码分割配置
splitChunks: {
chunks: "all", // 对所有模块都进行分割、
// 公共配置属性--以下是默认值
minSize: 20000, // 分割代码最小的大小
minRemainingSize: 0, // 类似于minSize,最后确保提取的文件大小不能为0
minChunks: 1, // 至少被引用的次数,满足条件才会代码分割
maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
maxInitialRequests: 30, // 入口js文件最大并行请求数量
enforceSizeThreshold: 50000, // 超过50kb一定会单独打包(此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)
// 单独组,哪些模块要打包到一个组 , 以上的属性都会被单独的 cacheGroups 属性设置继承,但是优先级最低
cacheGroups: {
// 组名
defaultVendors: {
// 指定chunks名称
name: "chunk-libs",
test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
priority: -10, // 权重(越大越高)
reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
},
default: {
// 其他没有写的配置会使用上面的默认值
minSize: 0, // 打包的最小文件体积,比如这里的的minSize就会 覆盖上面的 `minSize: 20000`
minChunks: 2, // 这里的minChunks权重更大
priority: -20,
reuseExistingChunk: true,
},
},
},
},
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# cacheGroups 配置的概念
我们自己的其他非异步加载的代码和 node_modules 中三方包的代码仍然混合在一起了,这样显然不利于浏览器缓存,因为业务代码改动是会很频繁的, 但是诸多第三方代码的改动是很少的,所以我们需要进一步将业务代码和 node_modules 代码拆分出来
其他比如:UI 库、依赖库等不常变化的代码都可以使用 cacheGroups 配置成单独的文件,这样这些依赖对应的 JS 文件 名称(主要是哈希值)就不行变动, 部署到线上时,客户端就能尽量使用客户端的缓存 JS 文件,无需重复请求
# 多入口文件引入
- 不详细写了,业务场景接触的少,不过 chrome 插件开发的话应该会用到,因为 chrome 插件开发的基础文件结构就很多
// webpack.config.js
const path = require("path");
module.exports = {
// 多入口
entry: {
main: "./src/main.js",
app: "./src/app.js",
},
output: {
// ...其他配置
},
plugins: [
// ... 其他配置
],
optimization: {
// 代码分割配置
splitChunks: {
chunks: "all", // 对所有模块都进行分割、
// 公共配置属性--以下是默认值
minSize: 20000, // 分割代码最小的大小
minRemainingSize: 0, // 类似于minSize,最后确保提取的文件大小不能为0
minChunks: 1, // 至少被引用的次数,满足条件才会代码分割
maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
maxInitialRequests: 30, // 入口js文件最大并行请求数量
enforceSizeThreshold: 50000, // 超过50kb一定会单独打包(此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)
// 单独组,哪些模块要打包到一个组 , 以上的属性都会被单独的 cacheGroups 属性设置继承,但是优先级最低
cacheGroups: {
defaultVendors: {
// 组名
test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
priority: -10, // 权重(越大越高)
reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
},
default: {
// 其他没有写的配置会使用上面的默认值
minSize: 0, // 打包的最小文件体积,比如这里的的minSize就会 覆盖上面的 `minSize: 20000`
minChunks: 2, // 这里的minChunks权重更大
priority: -20,
reuseExistingChunk: true,
},
},
},
},
mode: "production",
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 单入口文件引入
const path = require("path");
module.exports = {
// 单入口
entry: "./src/main.js",
output: {
// ...其他配置
},
plugins: [
// ...其他配置
],
mode: "production",
optimization: {
// 代码分割配置
splitChunks: {
chunks: "all", // 对所有模块都进行分割
// 以下是默认值
minSize: 20000, // 分割代码最小的大小
minRemainingSize: 0, // 类似于minSize,最后确保提取的文件大小不能为0
minChunks: 1, // 至少被引用的次数,满足条件才会代码分割
maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
maxInitialRequests: 30, // 入口js文件最大并行请求数量
enforceSizeThreshold: 50000, // 超过50kb一定会单独打包(此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)
cacheGroups: { // 组,哪些模块要打包到一个组
defaultVendors: { // 组名
filename: "static/js/bundle-libs.js", // 指定打包到文件夹
test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
priority: -10, // 权重(越大越高)
reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
},
default: { // 其他没有写的配置会使用上面的默认值
filename: "static/js/bundle_[contenthash:6].js", // 指定打包到文件夹
minChunks: 1, // 这里的minChunks权重更大, 引用一次就拆分
priority: -20,
reuseExistingChunk: true,
},
},
},
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
输出文件目录如下
- dist
- static
- css
- imgs
- js
- mainjs
- bundle-libs.js
- bundle_5392b7.js
- media
- index.html
2
3
4
5
6
7
8
9
10