概要
这个配置用来控制按需引入的包中的直接引入的包的打包。他表示按需引入的包中并行请求的最大数量。
一开始听起来肯定是大脑一片蒙蒙的感觉,不过其实很简单,可以理解为:当整个项目打包完之后,一个按需加载的包最终被拆分成n个包,maxAsyncRequests就是用来限制n的最大值。
接下来,还是按照老规矩,通过一系列的例子来实践一下。
准备工作
- 目录
root
——dist(打包之后的文件夹)
——node_modules(下载的包)
——src(项目脚本目录)
————entry(入口点脚本)
————modules(入口点中引入的模块)
——package.json(包管理文件)
——webpack.config.js(webpack配置文件)
- webpack配置
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: {
entry1: './src/entry/entry1.js',
entry2: './src/entry/entry2.js'
},
plugins: [
new CleanWebpackPlugin()
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
optimization: {
splitChunks: {
chunks: 'all',
maxAsyncRequests: 3,
minSize: 1,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 1,
priority: -20,
reuseExistingChunk: true
}
}
}
}
// default config
// optimization: {
// splitChunks: {
// chunks: 'async',
// minSize: 30000,
// minChunks: 1,
// maxAsyncRequests: 5,
// maxInitialRequests: 3,
// automaticNameDelimiter: '~',
// automaticNameMaxLength: 30,
// name: true,
// cacheGroups: {
// vendors: {
// test: /[\\/]node_modules[\\/]/,
// priority: -10
// },
// default: {
// minChunks: 2,
// priority: -20,
// reuseExistingChunk: true
// }
// }
// }
// }
}
- package.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"clean-webpack-plugin": "^3.0.0",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10"
}
}
案例
接下来,通过几个简单的案例,来分析maxAsyncRequests配置的控制规则。
- demo1
################################
webpack.config.js:
splitChunks.maxAsyncRequests设为2
################################
modules/add.js:
export default function add (a, b) {
return a + b
}
################################
modules/subtract.js
export default function subtract (a, b) {
return a - b
}
################################
modules/mutiply.js
export default function mutiply (a, b) {
return a * b
}
################################
modules/module.js
import add from './add'
import subtract from './subtract'
import multiply from './multiply'
export default function () {
console.log(add(3, 4) + subtract(10, 5) + multiply(1, 2))
}
################################
entry/entry1.js:
import('../modules/module').then(f => {
console.log('index', f())
})
################################
entry/entry2.js:
import add from '../modules/add'
import subtract from '../modules/subtract'
import multiply from '../modules/multiply'
console.log('index', add(1, 2) + subtract(4, 2) + multiply(1, 2))
通过npm run build进行打包,结果如下:
Hash: 699d2402a2a59dfa24c3
Version: webpack 4.41.5
Time: 85ms
Built at: 2020/01/19 上午9:28:13
Asset Size Chunks Chunk Names
0.bundle.js 333 bytes 0 [emitted]
5.bundle.js 211 bytes 5 [emitted]
default~entry1.bundle.js 165 bytes 1 [emitted] default~entry1
default~entry2.bundle.js 196 bytes 2 [emitted] default~entry2
entry1.bundle.js 2.22 KiB 3 [emitted] entry1
entry2.bundle.js 1.47 KiB 4 [emitted] entry2
Entrypoint entry1 = default~entry1.bundle.js entry1.bundle.js
Entrypoint entry2 = 0.bundle.js default~entry2.bundle.js entry2.bundle.js
[0] ./src/modules/add.js 54 bytes {0} [built]
[1] ./src/modules/subtract.js 59 bytes {0} [built]
[2] ./src/modules/multiply.js 59 bytes {0} [built]
[3] ./src/modules/module.js 183 bytes {5} [built]
[4] ./src/entry/entry1.js 70 bytes {1} [built]
[5] ./src/entry/entry2.js 185 bytes {2} [built]
我们会发现,add.js、subtract.js、multiply.js被打包到0.bundle.js,相当于entry1中按需引入的module/module.js包最终被拆分成0.bundle.js和5.bundle.js,刚刚好等于我们配置的最大上限值2。(这里注意下,webpack发现entry1中引入的module.js和entry2都直接引入了add.js、subtract.js和multiply.js,所以它很只能地将这三个包打包进同一个文件中,而不是分别单独打包。)
- demo2.js
################################
webpack.config.js:
splitChunks.maxAsyncRequests设为1
################################
modules/add.js:
export default function add (a, b) {
return a + b
}
################################
modules/subtract.js
export default function subtract (a, b) {
return a - b
}
################################
modules/mutiply.js
export default function mutiply (a, b) {
return a * b
}
################################
modules/module.js
import add from './add'
import subtract from './subtract'
import multiply from './multiply'
export default function () {
console.log(add(3, 4) + subtract(10, 5) + multiply(1, 2))
}
################################
entry/entry1.js:
import('../modules/module').then(f => {
console.log('index', f())
})
################################
entry/entry2.js:
import add from '../modules/add'
import subtract from '../modules/subtract'
import multiply from '../modules/multiply'
console.log('index', add(1, 2) + subtract(4, 2) + multiply(1, 2))
只是将maxAsyncRequests设为1,然后再次打包,结果如下:
Hash: 752b64e3f762dc224b3b
Version: webpack 4.41.5
Time: 84ms
Built at: 2020/01/19 上午9:38:39
Asset Size Chunks Chunk Names
4.bundle.js 482 bytes 4 [emitted]
default~entry1.bundle.js 143 bytes 0 [emitted] default~entry1
default~entry2.bundle.js 469 bytes 1 [emitted] default~entry2
entry1.bundle.js 2.22 KiB 2 [emitted] entry1
entry2.bundle.js 1.47 KiB 3 [emitted] entry2
Entrypoint entry1 = default~entry1.bundle.js entry1.bundle.js
Entrypoint entry2 = default~entry2.bundle.js entry2.bundle.js
[0] ./src/modules/add.js 54 bytes {1} {4} [built]
[1] ./src/modules/subtract.js 59 bytes {1} {4} [built]
[2] ./src/modules/multiply.js 59 bytes {1} {4} [built]
[3] ./src/modules/module.js 183 bytes {4} [built]
[4] ./src/entry/entry1.js 70 bytes {0} [built]
[5] ./src/entry/entry2.js 185 bytes {1} [built]
add.js、subtract.js、multiply.js并没有被单独打包出来,分别包含于4.bundle.js和default~entry2.bundle.js中。这恰好对应了我们配置的1,因为最大值为1,如果同demo1一样将add.js、subtract.js和multiply.js单独打包进一个文件中,相当于一个module被拆分成2个文件(即 > 1)。
- demo3
################################
webpack.config.js:
splitChunks.maxAsyncRequests设为2
同时entry入口新增entry3.js,如下:
entry: {
entry1: './src/entry/entry1.js',
entry2: './src/entry/entry2.js',
entry3: './src/entry/entry3.js',
}
################################
modules/add.js:
export default function add (a, b) {
return a + b
}
################################
modules/subtract.js
export default function subtract (a, b) {
return a - b
}
################################
modules/mutiply.js
export default function mutiply (a, b) {
return a * b
}
################################
modules/module.js
import add from './add'
import subtract from './subtract'
import multiply from './multiply'
export default function () {
console.log(add(3, 4) + subtract(10, 5) + multiply(1, 2))
}
################################
entry/entry1.js:
import('../modules/module').then(f => {
console.log('index', f())
})
################################
entry/entry2.js:
import add from '../modules/add'
import subtract from '../modules/subtract'
import multiply from '../modules/multiply'
console.log('index', add(1, 2) + subtract(4, 2) + multiply(1, 2))
################################
entry/entry3.js:
import add from '../modules/add'
import subtract from '../modules/subtract'
console.log('index', add(1, 2) + subtract(4, 2))
npm run build打包后,结果如下:
Hash: fbf4c99a34e2c4080633
Version: webpack 4.41.5
Time: 83ms
Built at: 2020/01/23 上午11:39:36
Asset Size Chunks Chunk Names
0.bundle.js 242 bytes 0 [emitted]
7.bundle.js 302 bytes 7 [emitted]
default~entry1.bundle.js 165 bytes 1 [emitted] default~entry1
default~entry2.bundle.js 289 bytes 2 [emitted] default~entry2
default~entry3.bundle.js 172 bytes 3 [emitted] default~entry3
entry1.bundle.js 2.22 KiB 4 [emitted] entry1
entry2.bundle.js 1.47 KiB 5 [emitted] entry2
entry3.bundle.js 1.47 KiB 6 [emitted] entry3
Entrypoint entry1 = default~entry1.bundle.js entry1.bundle.js
Entrypoint entry2 = 0.bundle.js default~entry2.bundle.js entry2.bundle.js
Entrypoint entry3 = 0.bundle.js default~entry3.bundle.js entry3.bundle.js
[0] ./src/modules/add.js 54 bytes {0} [built]
[1] ./src/modules/subtract.js 59 bytes {0} [built]
[2] ./src/modules/multiply.js 59 bytes {2} {7} [built]
[3] ./src/modules/module.js 183 bytes {7} [built]
[4] ./src/entry/entry1.js 70 bytes {1} [built]
[5] ./src/entry/entry2.js 185 bytes {2} [built]
[6] ./src/entry/entry3.js 171 bytes {3} [built]
其中add.js和subtract.js被单独打包进0.bundle.js,保证了module.js被拆分成了2个文件。(我们配置的上限为2)
假设我们没有限制,可以想到的是,add.js和subtract.js被拆分到一个文件中,multiply.js被拆分到一个文件中,所以我们会有这样一个疑惑,就是multiply.js为什么没有被拆出来,而是add.js、subtract.js被拆分出来。个人的猜想有两点:一个是add.js、subtract.js在三个入口点中均引入,而multiply.js在两个入口点中被引入;另外一个是add.js、subtract.js拆分出来的包肯定比单独multiply.js一个文件大。
为了得出webpack相应的打包规则,我们将multiply.js添加很多注释,使得其大小大于add.js和subtract.js大小总和。打包之后我们会发现结果和上面是一样的,所以可以得出:对于可能被打包的两种情况,被引入更多次的那个包会被优先打包出来。
那么引入的次数如果是一样的,那么是不是体积更大的会优先被打包出来呢,我们也可以测试一下。基于刚刚对demo3中multiply.js添加注释的代码,对于entry2.js只引入add.js,对于entry3.js只引入multiply.js,这个时候的打包结果为multiply.js被单独打包出来。
综上,我们得出的结论是:
a. 如果对于单独打包出来的模块有两种可能,被多次引入的那个包会被优先打包出来;
b. 同样的情况,如果两种情况下模块被引用的次数相同,体积大的那个模块或多个模块集会被打包出来;
注:如果两种情况下,情况一只包含一个模块,情况二则包含两个模块,并且两种情况下被引入的次数也是相同的,那么打包规则还是按照上面的b规则。
- demo4
################################
webpack.config.js:
在基于demo3的基础上将splitChunks.maxAsyncRequests设为3
################################
modules/add.js:
export default function add (a, b) {
return a + b
}
################################
modules/subtract.js
export default function subtract (a, b) {
return a - b
}
################################
modules/mutiply.js
export default function mutiply (a, b) {
return a * b
}
################################
modules/module.js
import add from './add'
import subtract from './subtract'
import multiply from './multiply'
export default function () {
console.log(add(3, 4) + subtract(10, 5) + multiply(1, 2))
}
################################
entry/entry1.js:
import('../modules/module').then(f => {
console.log('index', f())
})
################################
entry/entry2.js:
import add from '../modules/add'
import subtract from '../modules/subtract'
import multiply from '../modules/multiply'
console.log('index', add(1, 2) + subtract(4, 2) + multiply(1, 2))
################################
entry/entry3.js:
import add from '../modules/add'
import subtract from '../modules/subtract'
console.log('index', add(1, 2) + subtract(4, 2))
npm run build打包后,结果如下:
Hash: a3554617a9e78396ebfd
Version: webpack 4.41.5
Time: 272ms
Built at: 2020/01/23 上午11:43:49
Asset Size Chunks Chunk Names
0.bundle.js 242 bytes 0 [emitted]
1.bundle.js 153 bytes 1 [emitted]
7.bundle.js 211 bytes 7 [emitted]
default~entry1.bundle.js 172 bytes 2 [emitted] default~entry1
default~entry3.bundle.js 172 bytes 3 [emitted] default~entry3
entry1.bundle.js 2.22 KiB 4 [emitted] entry1
entry2.bundle.js 1.6 KiB 5 [emitted] entry2
entry3.bundle.js 1.47 KiB 6 [emitted] entry3
Entrypoint entry1 = default~entry1.bundle.js entry1.bundle.js
Entrypoint entry2 = 0.bundle.js 1.bundle.js entry2.bundle.js
Entrypoint entry3 = 0.bundle.js default~entry3.bundle.js entry3.bundle.js
[0] ./src/modules/add.js 54 bytes {0} [built]
[1] ./src/modules/subtract.js 59 bytes {0} [built]
[2] ./src/modules/multiply.js 59 bytes {1} [built]
[3] ./src/entry/entry2.js 185 bytes {5} [built]
[4] ./src/modules/module.js 183 bytes {7} [built]
[5] ./src/entry/entry1.js 70 bytes {2} [built]
[6] ./src/entry/entry3.js 171 bytes {3} [built]
add.js和subtract.js被单独打包进0.bundle.js,multiply.js被单独打包进1.bundle.js中。
如果继续将maxAsyncRequests配置项继续增大,结果还是一样。
这里将maxAsyncRequests设置为3,也就表示按需引入的module.js最多只能被拆分成三个bundle。
注:上面的打包结果我们会发现和之前的有些不一样,default.entry2.bundle.js没有被打包出来,这里主要是跟maxInitialRequests这个配置有关,该配置默认为3,这就表示单个入口点最多能被拆分的数量,上面这种情况,已经被拆分出0.bundle.js、1.bundle.js和entry2.js,数目已经达到3,default.entry2.bundle.js自然不会被打包出来。
- demo5
################################
webpack.config.js:
splitChunks.maxAsyncRequests设为2
基于demo3新增一个入口点,例如:
entry: {
entry1: './src/entry/entry1.js',
entry2: './src/entry/entry2.js',
entry3: './src/entry/entry3.js',
entry4: './src/entry/entry4.js',
}
################################
modules/add.js:
export default function add (a, b) {
return a + b
}
################################
modules/subtract.js
export default function subtract (a, b) {
return a - b
}
################################
modules/mutiply.js
export default function mutiply (a, b) {
return a * b
}
################################
modules/module.js
import add from './add'
import subtract from './subtract'
import multiply from './multiply'
export default function () {
console.log(add(3, 4) + subtract(10, 5) + multiply(1, 2))
}
################################
entry/entry1.js:
import('../modules/module').then(f => {
console.log('index', f())
})
################################
entry/entry2.js:
import add from '../modules/add'
import subtract from '../modules/subtract'
import multiply from '../modules/multiply'
console.log('index', add(1, 2) + subtract(4, 2) + multiply(1, 2))
################################
entry/entry3.js:
import add from '../modules/add'
import subtract from '../modules/subtract'
console.log('index', add(1, 2) + subtract(4, 2))
################################
entry/entry4.js:
import add from '../modules/add'
import subtract from '../modules/subtract'
console.log('index', add(1, 2) + subtract(4, 2))
打包后,结果如下:
Hash: 0edbe3d934d97c0d8908
Version: webpack 4.41.5
Time: 95ms
Built at: 2020/01/23 下午1:58:34
Asset Size Chunks Chunk Names
0.bundle.js 242 bytes 0 [emitted]
9.bundle.js 302 bytes 9 [emitted]
default~entry1.bundle.js 165 bytes 1 [emitted] default~entry1
default~entry2.bundle.js 289 bytes 2 [emitted] default~entry2
default~entry3.bundle.js 172 bytes 3 [emitted] default~entry3
default~entry4.bundle.js 172 bytes 4 [emitted] default~entry4
entry1.bundle.js 2.22 KiB 5 [emitted] entry1
entry2.bundle.js 1.47 KiB 6 [emitted] entry2
entry3.bundle.js 1.47 KiB 7 [emitted] entry3
entry4.bundle.js 1.47 KiB 8 [emitted] entry4
Entrypoint entry1 = default~entry1.bundle.js entry1.bundle.js
Entrypoint entry2 = 0.bundle.js default~entry2.bundle.js entry2.bundle.js
Entrypoint entry3 = 0.bundle.js default~entry3.bundle.js entry3.bundle.js
Entrypoint entry4 = 0.bundle.js default~entry4.bundle.js entry4.bundle.js
[0] ./src/modules/add.js 54 bytes {0} [built]
[1] ./src/modules/subtract.js 59 bytes {0} [built]
[2] ./src/modules/multiply.js 59 bytes {2} {9} [built]
[3] ./src/modules/module.js 183 bytes {9} [built]
[4] ./src/entry/entry1.js 70 bytes {1} [built]
[5] ./src/entry/entry2.js 185 bytes {2} [built]
[6] ./src/entry/entry3.js 171 bytes {3} [built]
[7] ./src/entry/entry4.js 171 bytes {4} [built]
其实就和demo3一样,add.js和subtract.js被单独打包到0.bundle.js,假如将maxAsyncRequests设置为3,效果和demo4一样。
上面的demo我们都是建立在chunks设置成all的情况下,如果设置成async,maxAsyncRequests配置还有效吗?当然是有效的。
总结
- maxAsyncRequests用来表示按需加载的模块其能拆分的最大数量;
- 如果对于单独打包出来的模块有两种可能,被多次引入的那个包会被优先打包出来;
- 同样的情况,如果两种情况下模块被引用的次数相同,体积大的那个模块或多个模块集会被打包出来;
- 该配置对于chunks为async和all情况下均可行,对于initial无效;