希沃ENOW大前端
公司官网:CVTE(广州视源股份)
团队:CVTE旗下未来教育希沃软件平台中心enow团队
本文作者:
Hello,大家好,我是小羽同学,一个平凡而又不甘于平凡的前端开发工程师。
今天的话,主要是想和大家聊聊小羽
是怎么把一个react老项目
的构建
时间减少70%+
的。
小羽最近接手了一个3年前
的老项目
看了下版本,react 16.0
+ ts
+ webpack4
,感觉还行
但是听说中间有接近一年
的时间没人维护,原本熟悉项目的人都溜了。
还没来的及详细研究代码,需求就到了。
只能硬着头皮
上了,还好有我的导师
和兵哥
从旁协助。
前期的开发也算是有惊无险
的渡过了吧。
最近几天刚开发完一个版本,然后发现我们项目的构建时间
实在太久了
。
XDM,如果我说打包
一个react项目居然要150s
,你们敢相信吗?
小羽
当时也是懵了
147s
,这可是2分半的时间。。。
看了一下cpu的利用率
,平均下来大概就是20%
左右。这个利用率也太低了吧?完全没有把cpu的性能发挥
出来。
happypack
然后小羽找了下webpack打包优化相关的包。然后发现了网上大多数都是说happypack
这个插件可以进行多线程
的优化。
那就整起呗。
npm install happypack --save-dev
复制代码
配置大概如下
const HappyPack = require('happypack');
const happyThreadPool = HappyPack.ThreadPool({size: require('os').cpus().length})
module.exports = {
...
module: {
rules: [
test: /\.js$/,
use: ['happypack/loader?id=js'],
],
plugins: [
...,
new HappyPack({
id: 'js',
loaders: ['babel-loader'],
threadPool: happyThreadPool,
})
]
}
}
复制代码
运行了一下
嗯,还不错,单js的转译就减少了20s
。
thread-loader
然而,小羽在css/less
打包优化的时候遇到了问题。
原因是css/less
中用到了mini-css-extract-plugin
这个样式抽离插件,删除这个插件后打包又是正常的。
查阅npm中的文档,发现作者由于对改项目的兴趣消退,在两年前已经断更了
。。。
然后作者给我们推荐了thread-loader
,那就转到thread-loader中去看看吧。
thread-loader
中提到,thread-loader中是无法使用自定义加载器 API
(即通过插件)。
而loader的加载顺序是从右往左
,从下往上
加载的。
像下面这个loader的加载顺序则是less-loader
=> css-loader
=> style-loader
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
],
},
复制代码
那么问题解决,只要我们在引用mini-css-extract-plugin
前加载thread-loader
就不会报错了。
完成所有的配置后,咱们再来尝试一下。
添加了thread-loader
的优化后打包构建的时间大概来到了120s
左右,和未优化前相比,减少了25-30s
。
然后cpu的利用率
也终于起来了,在loader编译阶段,利用率可以提升到40%
多。
terser-webpack-plugin
可是120s
的时间还是很长,这时候怎么处理呢?
其实在webpack的打包构建中耗时较多
的两个步骤应该是loader的转译
以及代码的混淆压缩
。(前提是得有这两个)
转译已经搞定了,那咱们处理混淆压缩吧。
看了下项目,发现用的是uglifyjs-webpack-plugin
这个插件进行混淆压缩。
那就看下官网吧
嗯,你确定没有在逗我吗?又是两年前断更了
,这。。。
我不想优化
了!!!
都是些啥玩意
啊!!!
哈哈哈,开个玩笑
。
优化那是必须得继续的。那就只能够继续查阅资料啦。
一个偶然的机会,发现了咱们接下来的主角——terser-webpack-plugin
记住,如果是webpack4
的版本那么也要安装terser-webpack-plugin
v4的版本。v5的版本是给webpack5
来使用的。
小羽这边接受的项目是webpack4
,那就用v4
的,然后看了下插件的版本。v4最新的
是4.2.3
npm install terser-webpack-plugin@4.2.3 --save-dev
复制代码
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
...
optimization:{
minimizer: [
new TerserPlugin({
parallel: require('os').cpus().length - 1,
terserOptions:{
compress:{
inline:false
},
mangle: {
safari10: true
}
}
})
]
}
}
复制代码
parallel
参数是用来设置你启动的线程数
的。require(‘os’).cpus().length – 1,代表获取你电脑所有线程-1的数量。
然后这里得提一下,
并不是
启动的线程数量越多就越好
的(包括前面的thread-loader)。因为我们每启动一个线程都是需要消耗一定的时间的,这个时间约为
600ms
。举个?,假如现在你用的是一台8核16线程的电脑。咱们把所有的线程都启动起来,那么启动的时间约为
9.6s
。但是当咱们的项目比较小,原本打包的时间可能就
5、6s
,压缩的时间可能连600ms
都不到,这样的话咱们的打包优化就变成了负优化
了。所以并不是
每一个项目
都需要开启
多线程的。是否要开启?开启多少个线程?这些都是需要看情况的。
terser-webpack-plugin
的terserOptions
参数基本与uglifyjs-webpack-plugin
中的uglifyOptions
是一致的,直接平滑升级,美滋滋~
那咱们来测试一下吧~
构建时间约为41s
,nice~
然后在看一下咱们混淆压缩时候的cpu负载
也是彪了上来,cpu负载最高可到92%
。
最后咱们计算一下
未优化前147s
,优化后41s
,一共减少了106s
,减少了快两分钟
的时间。
那咱们在计算一下提升的性能,(147-41)/147≈0.72。提升了72%
。
小结
小羽在本文中和小伙伴们聊了下在工作中是如何优化
一个老项目的webpack打包构建经历,向小伙伴们介绍了happypack
、thread-loader
以及terser-webpack-plugin
的用法。希望能够给小伙伴们在webpack
的构建中带来一些帮助
,也希望小伙伴们可以从中得到一些启发
~