webpack 构建优化

两个问题

  1. 包体积过大
  2. 打包速度太慢

优化1 webpack.DllPlugin

能加快打包速度,减小自身业务代码打包后的体积,但代码总体积(包含了第三方库)反而增大

项目中我们要将第三方库的代码单独打包,一般采用的方式是 webpack.optimize.CommonsChunkPlugin 这个插件。

1
2
3
4
5
6
7
8
9
entry: {
vendor: ['react', 'react-dom'] // 类库
};

new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.js',
minChunks: Infinity
}),

然而,用这种方式,每次我们重新构建代码时,vendor 的代码都要重新构建,从而使得构建的速度变慢。

webpack.DllPlugin 就可以解决这个问题,将第三方库事先编译为dll库,之后构建项目自身源码时,就不许要重新构建dll库中的代码。

首先,我们需要编写 webpack.dll.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 webpack = require('webpack');

module.exports = {
entry: {
vendor: ['react', 'react-dom', 'antd']
},
output: {
path: path.join(__dirname, 'build'),
filename: '[name].dll.js',
library: '[name]_library'
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, 'build', '[name]-manifest.json'),
name: '[name]_library'
})
]
};

其实,webpack 中的插件也都可以用在 webpack.dll 配置文件中。

执行 webpack --config webpack.dll.config.js 后,即可在 build 目录下找到生成的 dll bundle 和对应的 manifest 文件。

1
2
3
4
5
6
7
8
9
> webpack --config webpack.dll.config.js

Hash: 674d064bed0bcc476713
Version: webpack 1.14.0
Time: 4349ms
Asset Size Chunks Chunk Names
vendor.dll.js 3.59 MB 0 [emitted] vendor
[0] dll vendor 12 bytes {0} [built]
+ 913 hidden modules

然后,我们在 webpack.config.js 中配置 DLLReferencePlugin 插件。

1
2
3
4
5
6
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./build/vendor-manifest.json')
})
]

在 html 中,需要手动引入 dll 库

1
<script src="/build/vendor.dll.js"></script>

性能对比

首次构建:(build)
采用 CommonsChunkPlugin :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Hash: 6ade5ef99f806b597685
Version: webpack 1.14.0
Time: 13349ms
Asset Size Chunks Chunk Names
program-list/index.js.map 18.7 kB 2 [emitted] program-list/index
index/index.js 26.2 kB 0 [emitted] index/index
program-list/index.js 19.3 kB 2 [emitted] program-list/index
theme-manage/index.js 622 kB 3 [emitted] theme-manage/index
vendor.js 1.43 MB 4 [emitted] vendor
index/index.js.map 19.3 kB 0 [emitted] index/index
new-theme/index.js.map 499 kB 1 [emitted] new-theme/index
new-theme/index.js 446 kB 1 [emitted] new-theme/index
theme-manage/index.js.map 727 kB 3 [emitted] theme-manage/index
vendor.js.map 1.71 MB 4 [emitted] vendor
index.html 2.45 kB [emitted]
new-theme.html 2.46 kB [emitted]
program-list.html 2.47 kB [emitted]
theme-manage.html 2.47 kB [emitted]

采用 DllPlugin :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Hash: 6f2755df167fdbf28a55
Version: webpack 1.14.0
Time: 8209ms
Asset Size Chunks Chunk Names
program-list/index.js.map 10.4 kB 2 [emitted] program-list/index
index/index.js 26.1 kB 0 [emitted] index/index
program-list/index.js 12 kB 2 [emitted] program-list/index
theme-manage/index.js 48.4 kB 3 [emitted] theme-manage/index
vendor.js 303 kB 4 [emitted] vendor
index/index.js.map 19.3 kB 0 [emitted] index/index
new-theme/index.js.map 99.5 kB 1 [emitted] new-theme/index
new-theme/index.js 111 kB 1 [emitted] new-theme/index
theme-manage/index.js.map 39.5 kB 3 [emitted] theme-manage/index
vendor.js.map 358 kB 4 [emitted] vendor
index.html 2.5 kB [emitted]
new-theme.html 2.51 kB [emitted]
program-list.html 2.52 kB [emitted]
theme-manage.html 2.52 kB [emitted]

可以看到,用 DllPlugin 能比 CommonsChunkPlugin 约5s。这里的例子是一个多页面构建的例子。
注意,此处我们虽然看到 DllPlugin 打包出来的文件要比 CommonsChunkPlugin 的小,但其实是我们把第三方库提取到了 vendor.dll.js 中的原因,加上 vendor.dll.js 中的文件,DllPlugin 打包总文件体积更大。

模块热加载(rebuild)
采用 CommonsChunkPlugin :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Hash: d8187730060863aecaad
Version: webpack 1.14.0
Time: 2478ms
Asset Size Chunks Chunk Names
6ade5ef99f806b597685.hot-update.json 36 bytes [emitted]
index/index.js 26.2 kB 0 index/index
program-list/index.js 19.3 kB 2 program-list/index
theme-manage/index.js 622 kB 3 theme-manage/index
vendor.js 1.43 MB 4 [emitted] vendor
1.6ade5ef99f806b597685.hot-update.js 6.41 kB 1 [emitted] new-theme/index
new-theme/index.js 446 kB 1 [emitted] new-theme/index
index/index.js.map 19.3 kB 0 index/index
program-list/index.js.map 18.7 kB 2 program-list/index
theme-manage/index.js.map 727 kB 3 theme-manage/index
new-theme/index.js.map 499 kB 1 [emitted] new-theme/index
1.6ade5ef99f806b597685.hot-update.js.map 4.41 kB 1 [emitted] new-theme/index
vendor.js.map 1.71 MB 4 [emitted] vendor

采用 DllPlugin :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Hash: ca95bad33ad492f0a11b
Version: webpack 1.14.0
Time: 1005ms
Asset Size Chunks Chunk Names
456baae3287b91efa0d4.hot-update.json 36 bytes [emitted]
index/index.js 26.1 kB 0 index/index
program-list/index.js 12 kB 2 program-list/index
theme-manage/index.js 48.4 kB 3 theme-manage/index
vendor.js 303 kB 4 [emitted] vendor
1.456baae3287b91efa0d4.hot-update.js 6.4 kB 1 [emitted] new-theme/index
new-theme/index.js 111 kB 1 [emitted] new-theme/index
index/index.js.map 19.3 kB 0 index/index
program-list/index.js.map 10.4 kB 2 program-list/index
theme-manage/index.js.map 39.5 kB 3 theme-manage/index
new-theme/index.js.map 99.5 kB 1 [emitted] new-theme/index
1.456baae3287b91efa0d4.hot-update.js.map 4.41 kB 1 [emitted] new-theme/index
vendor.js.map 358 kB 4 [emitted] vendor

追求极致体验,dll 值得拥有。

另外还需注意到的一点是,antd 这个包非常大,大概有 2.6m,用 dll 的方式,就一次把整个antd 的包都打入 vendor.dll.js 中,使得 vendor.dll.js 非常大。这在开发环境时,为了追求打包速度,可以不考虑包大小。在生产环境下,建议还是采用 antd 推荐的 babel 插件,做按需加载处理,从而减小包的总大小

优化2 HappyPack

配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const HappyPack = require('happypack');

plugins: [
new HappyPack({
id: 'jsx',
threads: 4,
loaders: ['react-hot', 'babel?' + JSON.stringify({
presets: ['es2015', 'stage-0', 'react']
})]
})
]

loaders: [
{
test: /\.(js|jsx)$/,
//loader: 'react-hot!babel-loader',
loaders: ['happypack/loader?id=jsx'],
include: [].concat(
config.additionalPaths,
[ path.join(__dirname, '/../src') ]
)
}
]

采用 happypack 能进一步将构建时间从10s提升至5s。

以上两个优化都是优化了构建速度,然而并没能减小代码编译后包的体积大小,这是以后需要继续探索改进的地方。

参考文档:

  1. 开发工具心得:如何 10 倍提高你的 Webpack 构建效率
  2. webpack使用优化(基本篇)
  3. webpack使用优化(react篇)
  4. webpack 的 dll 功能
  5. 彻底解决Webpack打包性能问题
  6. 使用 webpack + react + redux + es6 开发组件化前端项目
  7. happypack github
  8. webpack 2.1 beta20 + happypack 多线程