webpack之优化篇(二)
优化配置提高构建速度
在webpack4中,一些默认插件由 optimization 配置替代了,如下:
- CommonsChunkPlugin废弃,由
optimization.splitChunks
和optimization.runtimeChunk
替代,前者拆分代码,后者提取runtime代码。原来的CommonsChunkPlugin产出模块时,会包含重复的代码,并且无法优化异步模块,minchunks的配置也较复杂,splitChunks解决了这个问题;另外,将 optimization.runtimeChunk 设置为true(或{name: “manifest”}),便能将入口模块中的runtime部分提取出来。 - NoEmitOnErrorsPlugin 废弃,由
optimization.noEmitOnErrors
替代,生产环境默认开启。 - NamedModulesPlugin 废弃,由
optimization.namedModules
替代,生产环境默认开启。 - ModuleConcatenationPlugin 废弃,由
optimization.concatenateModules
替代,生产环境默认开启。 - optimize.UglifyJsPlugin 废弃,由
optimization.minimize
替代,生产环境默认开启
optimization 还提供了如下默认配置:
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // 只打包初始时依赖的第三方
},
elementUI: {
name: 'chunk-elementUI', // 单独将 elementUI 拆包
priority: 20, // 权重要大于 libs 和 app 不然会被打包进 libs 或者 app
test: /[\\/]node_modules[\\/]element-ui[\\/]/
}
}
},
runtimeChunk: 'single',
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
mangle: {
safari10: true
},
// 清除生产环境的控制台输出
compress: {
warnings: false,
drop_debugger: true,
drop_console: true
}
},
sourceMap: config.build.productionSourceMap,
cache: true,
parallel: 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
webpack优化方案
- 缩小编译范围,减少不必要的编译工作,即
modules、mainFields、noParse、includes、exclude、alias
等。 - 通过
externals
配置来提取常用库,引用cdn。 - 使用缓存和dllplugin。
webpack-parallel-uglify-plugin
和happypack
多核构建项目
缩小编译范围,减少不必要的编译工作
缩小编译范围,减少不必要的编译工作,即 modules、mainFields、noParse、includes、exclude、alias
等
const resolve = dir => path.join(__dirname, '..', dir);
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath:
process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src')
}
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
include: [
resolve('src'),
resolve('test'),
resolve('node_modules/webpack-dev-server/client')
]
},
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
include: [resolve('src/icons')],
options: {
symbolId: 'icon-[name]'
}
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
exclude: [resolve('src/icons')],
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
]
}
}
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
50
51
52
通过 externals 配置来提取常用库,引用cdn
如果我们想引用一个库,但是又不想让webpack打包,并且又不影响我们在程序中以CMD、AMD或者window/global全局等方式进行使用,那就可以通过配置externals。这个功能主要是用在创建一个库的时候用的,但是也可以在我们项目开发中充分使用。
externals:["React","jQuery"]
dllplugin启用预编译
第三方库以 node_modules 为代表,它们庞大得可怕,却又不可或缺。
处理第三方库的姿势有很多,其中,Externals 不够聪明,一些情况下会引发重复打包的问题;而 CommonsChunkPlugin 每次构建时都会重新构建一次 vendor;出于对效率的考虑,我们这里为大家推荐 DllPlugin。
DllPlugin 是基于 Windows 动态链接库(dll)的思想被创作出来的。这个插件会把第三方库单独打包到一个文件中,这个文件就是一个单纯的依赖库。这个依赖库不会跟着你的业务代码一起被重新打包,只有当依赖自身发生版本变化时才会重新打包。
用 DllPlugin 处理文件,要分两步走:
- 基于 dll 专属的配置文件,打包 dll 库
- 基于 webpack.config.js 文件,打包业务代码
AutoDllPlugin:解放你的配置负担
webpack插件
autodll-webpack-plugin
// 文件目录:configs/webpack.common.js
const path = require('path');
const AutoDllPlugin = require('autodll-webpack-plugin'); // 第 1 步:引入 DLL 自动链接库插件
module.exports = {
// ......
plugins: [
// 第 2 步:配置要打包为 dll 的文件
new AutoDllPlugin({
inject: true, // 设为 true 就把 DLL bundles 插到 index.html 里
filename: '[name].dll.js',
context: path.resolve(__dirname, '../'), // AutoDllPlugin 的 context 必须和 package.json 的同级目录,要不然会链接失败
entry: {
react: [
'react',
'react-dom'
]
}
})
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
抛弃 DLL:Vue & React 官方的共同选择
wepack4已经抛弃了dll,vue-cli和react-create-app都抛弃了dll
更好用的插件HardSourceWebpackPlugin
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
// ......
plugins: [
new HardSourceWebpackPlugin() // <- 直接加入这行代码就行
]
}
2
3
4
5
6
7
8
Happypack——将 loader 由单进程转为多进程
大家知道,webpack 是单线程的,就算此刻存在多个任务,你也只能排队一个接一个地等待处理。这是 webpack 的缺点,好在我们的 CPU 是多核的,Happypack 会充分释放 CPU 在多核并发方面的优势,帮我们把任务分解给多个子进程去并发执行,大大提升打包效率。
HappyPack
的使用方法也非常简单,只需要我们把对 loader 的配置转移到 HappyPack 中去就好,我们可以手动告诉 HappyPack 我们需要多少个并发的进程:
const HappyPack = require('happypack')
// 手动创建进程池
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length })
module.exports = {
module: {
rules: [
...
{
test: /\.js$/,
// 问号后面的查询参数指定了处理这类文件的HappyPack实例的名字
loader: 'happypack/loader?id=happyBabel',
...
},
],
},
plugins: [
...
new HappyPack({
// 这个HappyPack的“名字”就叫做happyBabel,和楼上的查询参数遥相呼应
id: 'happyBabel',
// 指定进程池
threadPool: happyThreadPool,
loaders: ['babel-loader?cacheDirectory']
})
],
}
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
构建结果体积压缩
文件结构可视化,找出导致体积过大的原因
这里为大家介绍一个非常好用的包组成可视化工具——webpack-bundle-analyzer
,配置方法和普通的 plugin 无异,它会以矩形树图的形式将包内各个模块的大小和依赖关系呈现出来,格局如官方所提供这张图所示.
在使用时,我们只需要将其以插件的形式引入:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
}
2
3
4
5
6
7