关于webpack的一些点

记录webpack的一些基本概念及相关优化。

webpack 核心概念

  • entry: 入口起点,指示 webpack 构建内部依赖的开始。
  • output: 构建结果的输出及文件命名。
  • moudule: webpack 里一切皆为模块,一个模块对应一个文件,webpack 会从 Entry 开始递归找出所有依赖模块。
  • loader: webpack 只能理解 JavaScript 和 JSON 文件。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。loader 可以理解为一个转换器。
  • plugin: loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。

提高 webpack 打包速度

DllPlugin

之前我们利用 CommonsChunkPlugin 来分拆公共模块,但是在webpack v4之后已经被移除,现在利用DLLPlugin 和 DLLReferencePlugin 来拆分 bundles,同时还大大提升了构建的速度。

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
// webpack-dll.js
const options = {
entry: {
vendors: ['react', 'react-dom', 'react-router-dom'],
},
output: {
path: path.join(__dirname, '../dist/'),
filename: '[name].js',
library: '[name]'
},
plugins: [
new webpack.DllPlugin({
context: __dirname,
path: path.join(__dirname, 'manifest.json'),
name: '[name]'
})
],
mode: 'development'
};

// webpack.dev.config.js
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./manifest.json'),
name: 'vendors'
}),
// ....
}

利用 HappyPack 提高打包速度

在 webpack 构建过程中,随着项目的文件越来越多,需要解析和处理大量的文件。但是由于 node.js 是单线程,所以构建过程中并不能并行的去处理文件,从而造成了构建时间的增加。
HappyPack 是 webpack 的一个插件,可以通过 HappyPack 可以将构建任务分解给多个子进程并发的执行,子进程处理完后,再将结果通知给主进程,从而提高了 webpack 的构建速度。

HappyPack 对 file-loader、url-loader 支持不友好,不建议对该 loader 使用

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
const happyThreadPool = HappyPack.ThreadPool({size: 4});
// module.rules 中配置
{
test: /\.js$/,
include: [
path.resolve(__dirname, '../src'),
],
use: ['happypack/loader?id=js'],
}

// plugins 中配置
new HappyPack({
id: 'js',
verbose: false,
// 使用多少子进程来进行编译,一般设置为4为最佳
// threads: 4,
// 设置 HappyPack 插件中所有 loaders 均采用子进程数
threadPool: happyThreadPool,
loaders: [
{
loader: 'babel-loader',
query: {
cacheDirectory: true,
}
}
]
}),

optimization

从 webpack4 开始,会根据 mode 来执行不同的优化。不过所有的优化,还是可以手动配置和重写的。

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
37
38
39
40
41
42
43
44
45
46
47
48
module.exports = {
optimization: {
minimize: true, // production模式下,默认为 true, 告知 webpack 使用 TerserPlugin 压缩 bundle.
// 允许你通过提供一个或多个定制化的 TerserPlugin实例,来覆盖默认压缩工具。
minimizer: [
new UglifyJsPlugin({
sourceMap: true, // cheap-source-map options don't work with this plugin.
parallel: true, // 使用多进程提升构建速度,默认为 os.cpus().length - 1, 可手动设置。
uglifyOptions: {
compress: {
warnings: true, // 显示警告
drop_debugger: true, // 去除debugger
drop_console: true // 去除console
}
}
})
],
runtimeChunk: {
name: 'manifest'
},
splitChunks: {
chunks: 'all', // 块的范围,有三个可选值:initial(初始块)、async(按需加载块)、all(全部块),默认为all
cacheGroups: {
// 基本类库
vendor: {
test: /[\/]node_modules[\/]/,
chunks: 'initial',
name: 'vendor',
priority: 10,
enforce: true
},
//公共组
common: {
name: 'comomn',
test: path.join(__dirname, '..', 'src/lib'),
minChunks: 2, // 最小共用次数
priority: 5,
reuseExistingChunk: true
},
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
},
}
}
}
}