背景

针对一个多页面向目来讲,我们希望每个包的体积都更小一些。

方案

可以使用webpack的提供的三种分离方案

  • 入口起点:使用 entry 配置手动地分离代码。
  • 防止重复:使用 CommonsChunkPlugin 去重和分离 chunk。
  • 动态导入:通过模块的内联函数调用来分离代码。

写法

使用 entry 配置手动地分离代码。

清理一下文件并新增一个生产与开发环境及通用配置的config文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
       webpack_learn
|- node_modules
|- package.json
+ |- webpack.config.js
- |- webpack.common.js
- |- webpack.dev.js
- |- webpack.prod.js
|- yarn.lock
|- src
|- let.js
|- get.js
|- index.js
|- math.js
|- dist
|- bundle.js
|- index.html

修改新增的配置文件内容

修改 webpack.config.js 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
math: './src/math.js'
},
plugins: [
new CleanWebpackPlugin(),
new HTMLWebpackPlugin({
title: 'Code Splitting'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};

然后修改package.json中的scripts快捷指令

1
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
{
"dependencies": {
"babel-loader": "^8.0.6",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^5.1.1",
"html-webpack-plugin": "^3.2.0",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.1",
"webpack-merge": "^4.2.2"
},
"name": "webpack_learn",
"sideEffects": false,
"version": "1.0.0",
"main": "index.js",
"devDependencies": {
"@babel/core": "^7.7.7",
"@babel/preset-env": "^7.7.7",
"babel-core": "^6.26.3",
"babel-preset-env": "^1.7.0"
},
"scripts": {
+ "build": "webpack --config webpack.config.js",
- "build": "webpack --config webpack.prod.js",
- "serve": "webpack-dev-server --open --config webpack.dev.js",
"watch": "webpack --watch",
"dev": "webpack --mode development",
"product": "webpack --mode production",
"testParams": "webpack --mode production --env.production product --param1 1 --param2 2 --explane 这是一个说明",
"showColorAndProgress": "webpack --progress --colors",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"description": ""
}

修改一下index.js的内容

1
2
3
let name = require('./let.js');
let sayName = require('./get.js');
sayName('大家好,我的名字是'+name)

然后执行打包指令

1
npm run build #也可以yarn build 打包生产环境

index.bundle.js
打包后可以看到编译的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
       webpack_learn
|- node_modules
|- package.json
|- webpack.config.js
|- yarn.lock
|- src
|- let.js
|- get.js
|- index.js
|- math.js
|- dist
- |- bundle.js
- |- index.html
+ |- index.html
+ |- index.bundle.js
+ |- math.bundle.js

并且index.html中的内容如下,引入了两个js文件,而且,index.jsmath.js中的代码被分离开了,达成了通过entry的配置方式进行分离

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Code Splitting</title>
</head>
<body>
<script type="text/javascript" src="index.bundle.js"></script>
<script type="text/javascript" src="math.bundle.js"></script>
</body>
</html>

使用 CommonsChunkPlugin 去重和分离 chunk

CommonsChunkPlugin 插件可以将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk。

继续修改文件目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
       webpack_learn
|- node_modules
|- package.json
|- webpack.config.js
|- yarn.lock
|- src
|- let.js
|- get.js
|- index.js
+ |- index2.js
|- math.js
|- dist
|- index.html
|- index.bundle.js
|- math.bundle.js

1
2
3
4
//index2.js
+ let name = require('./let.js');
+ let sayName = require('./get.js');
+ sayName('大家好,我的名字2是'+name)

修改 webpack.config.js 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
index2: './src/index2.js',
math: './src/math.js'
},
plugins: [
new CleanWebpackPlugin(),
new HTMLWebpackPlugin({
title: 'Code Splitting'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};

然后执行打包指令

1
npm run build #也可以yarn build 打包生产环境

然后可以看到,index2.bundle.jsindex.bundle.js中,均出现了重复的代码

1
([function(e,t){e.exports="小明"},function(e,t){e.exports=function(e){console.log(e)}}

为了解决这种情况,可以使用CommonsChunkPlugin 去重和分离 chunk

修改 webpack.config.js 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
+ const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
index2: './src/index2.js',
math: './src/math.js'
},
plugins: [
new CleanWebpackPlugin(),
new HTMLWebpackPlugin({
title: 'Code Splitting'
- })
+ }),
+ new webpack.optimize.CommonsChunkPlugin({
+ name: 'common' // 指定公共 bundle 的名称。
+ })
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};

然后执行打包指令

1
npm run build #也可以yarn build 打包生产环境

此时打包报错了,提示信息

1
Error: webpack.optimize.CommonsChunkPlugin has been removed, please use config.optimization.splitChunks instead.

修改 webpack.config.js 文件

1
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
    const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
- const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
index2: './src/index2.js',
math: './src/math.js'
},
plugins: [
new CleanWebpackPlugin(),
new HTMLWebpackPlugin({
title: 'Code Splitting'
- }),
- new webpack.optimize.CommonsChunkPlugin({
- name: 'common' // 指定公共 bundle 的名称。
- })
],

+ optimization: {
+ splitChunks: {
+ cacheGroups: {
+ commons: {
+ name: "commons",
+ chunks: "all",
+ minChunks: 2
+ }
+ }
+ }
+ },
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};

webpack.optimize.CommonsChunkPlugin这个模块被移除了,请使用config.optimization.splitChunks代替,查询文档地址

但是我们发现,再次打包,也没有单独生成一个我们命名的commons.bundle.js

初步怀疑是,公共代码包里的代码体积过小,导致的没有打包,我们将index.jsindex2.js中引入一个巨大的lodash模块再来尝试一下

1
2
3
4
5
6
7
8
9
10
11
//index.js
+ import _ from 'lodash';
let name = require('./let.js');
let sayName = require('./get.js');
sayName('大家好,我的名字是'+name)

//index2.js
+ import _ from 'lodash';
let name = require('./let.js');
let sayName = require('./get.js');
sayName('大家好,我的名字2是'+name)

然后执行打包指令

1
npm run build #也可以yarn build 打包生产环境

打包结果如下

Asset Size Chunks Chunk Names
commons.bundle.js 71.1 KiB 0 [emitted] commons
index.bundle.js 1.64 KiB 1 [emitted] index
index.html 379 bytes [emitted]
index2.bundle.js 1.58 KiB 2 [emitted] index2
math.bundle.js 1.18 KiB 3 [emitted] math

可以看到,lodash模块被打包进了commons.bundle.js从而实现了公共代码的分离