前言
随着项目越来越复杂,可能你们会有同样的感触,上了趟厕所回来,项目还没构建完成。然而测试还一直在催命。或许这时候你就应该去考虑下,如何去优化我们的构建速度。
优化方案
1. 优化babel-loader
babel-loader在执行的时候,可能会产生一些运行期间重复的公共文件,造成代码体积大冗余,同时也会减慢编译效率,因此我们可以通过添加cacheDirectory
开启babel缓存。
{
test: /.m?js$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader",
options: {
cacheDirectory: true
},
},
},
复制代码
2. noParse
该配置项可以让webpack
忽略对部分未采用模块化文件的递归解析和处理,该忽略的文件不能包含import,require, define
等模块化语句。
module.exports = {
module: {
noParse: /jquery|xxjs/
}
}
复制代码
3. happyPack(多进程打包)
由于 JavaScript 是单线程模型,要想发挥多核 CPU 的能力,只能通过多进程去实现,而无法通过多线程实现。happyPack
的思想是使用多个子进程去解析和编译JS,css,等,这样就可以并行处理多个子任务,多个子任务完成后,再将结果发到主进程中。
- 安装
$ npm install happypack --save-dev
复制代码
- 使用
happypack 只是作用在 loader 上,使用多个进程同时对文件进行编译。
1.将常用的 loader
替换为 happypack/loader
const HappyPack = require('happypack');
module.exports = {
...
module: {
rules: [
test: /.js$/,
// use: ['babel-loader?cacheDirectory'] 之前是使用这种方式直接使用 loader
// 现在用下面的方式替换成 happypack/loader,并使用 id 指定创建的 HappyPack 插件
use: ['happypack/loader?id=babel'],
// 排除 node_modules 目录下的文件
exclude: /node_modules/
]
}
}
复制代码
2.创建 HappyPack 插件
代码语言:javascript复制const HappyPack = require('happypack');
module.exports = {
...
module: {
rules: [
test: /.js$/,
// use: ['babel-loader?cacheDirectory'] 之前是使用这种方式直接使用 loader
// 现在用下面的方式替换成 happypack/loader,并使用 id 指定创建的 HappyPack 插件
use: ['happypack/loader?id=babel'],
// 排除 node_modules 目录下的文件
exclude: /node_modules/
]
},
plugins: [
...,
new HappyPack({
/*
* 必须配置 id 标识符,要和 rules 中指定的 id 对应起来
*/
id: 'babel',
// 需要使用的 loader,用法和 rules 中 Loader 配置一样
// 可以直接是字符串,也可以是对象形式
loaders: ['babel-loader?cacheDirectory']
})
]
}
复制代码
这样 Happypack 的使用就配置完了,运行项目,可以看到控制台打印如下提示:
代码语言:javascript复制Happy[babel]: Version: 5.0.1. Threads: 3
Happy[babel]: All set; signaling webpack to proceed.
复制代码
说明配置生效了。关于开启多进程,这里要注意下:
- 项目较大,打包较慢,开启多进程能提高构建速度
- 项目较小,打包很快,开启多进程会降低速度(进程开销)
如果大家对happypack的使用想更深入些,推荐传送门这篇文章讲的更系统些,建议大家阅读。
4. ParallelUglifyPlugin(多进程压缩js)
webpack
默认提供了UglifyJS
插件来压缩JS
代码,但是它使用的是单线程压缩代码,也就是说多个js
文件需要被压缩,它需要一个个文件进行压缩。所以说在正式环境打包压缩代码速度非常慢(因为压缩JS
代码需要先把代码解析成用Object
抽象表示的AST
语法树,再去应用各种规则分析和处理AST
,导致这个过程耗时非常大)。使用UglifyJS
压缩代码如下:
module.exports = {
plugins: [
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
]
}
复制代码
ParallelUglifyPlugin
插件则会开启多个子进程,把对多个文件压缩的工作分别给多个子进程去完成,但是每个子进程还是通过UglifyJS去压缩代码。无非就是变成了并行处理该压缩了,并行处理多个子任务,效率会更加的提高。
- 安装
npm i -D webpack-parallel-uglify-plugin
复制代码
- 使用
// 引入 ParallelUglifyPlugin 插件
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
module.exports = {
plugins: [
// 使用 ParallelUglifyPlugin 并行压缩输出JS代码
new ParallelUglifyPlugin({
// 传递给 UglifyJS的参数如下:
uglifyJS: {
output: {
/*
是否输出可读性较强的代码,即会保留空格和制表符,默认为输出,为了达到更好的压缩效果,
可以设置为false
*/
beautify: false,
/*
是否保留代码中的注释,默认为保留,为了达到更好的压缩效果,可以设置为false
*/
comments: false
},
compress: {
/*
是否删除代码中所有的console语句,默认为不删除,开启后,会删除所有的console语句
*/
drop_console: true,
/*
是否内嵌虽然已经定义了,但是只用到一次的变量,比如将 var x = 1; y = x, 转换成 y = 5, 默认为不
转换,为了达到更好的压缩效果,可以设置为false
*/
collapse_vars: true,
/*
是否提取出现了多次但是没有定义成变量去引用的静态值,比如将 x = 'xxx'; y = 'xxx' 转换成
var a = 'xxxx'; x = a; y = a; 默认为不转换,为了达到更好的压缩效果,可以设置为false
*/
reduce_vars: true
}
}
}),
]
}
复制代码
这里同样推荐篇文章传送门
5. IgnorePlugin
IgnorePlugin插件的主要作用是,在打包时可以忽略无用的的内容,减小打包体积。具体使用可以参考官网的例子传送门
6. DllPlugin
- 作用
把复用性较高的第三方模块打包到动态链接库中,在不升级这些库的情况下,动态库不需要重新打包,每次构建只重新打包业务代码。
- 使用
这里可以参考传送门这篇文件,这个大哥讲的比较详细,这里不再赘述。
最后
除了在打包上做优化之外,在平常写代码中,我们也同样应该注意,考虑性能问题,考虑包的体积。避免因为使用某个库的及少的api而去引入一个很大的库。学会使用按需引入,使用懒加载等。