说在前面
随着项目逐渐开发完善,项目工程越来越大,每次修改完前端代码等待编译的时间很长,严重影响开发效率,所以针对项目打包和启动编译过程进行了研究以及改进,本文会以叙事的口吻来逐步介绍优化的过程和思路,希望能帮助有相同问题或者类似问题的小伙伴一些启发。
首先给大家看一看最初项目打包以及启动所需的时间:
项目打包:
项目启动:
改动后项目重新编译:
打包过程中会输出一系列的打包日志,每时每刻都在处理哪些内容,在经过一番思考过后我准备从这个点下手,发现到底是哪些操作影响了构建效率。
cache-loader
在此之前,简单了解一下cache-loader
,我们会惊奇的发现一件事情,当我们第一次运行项目之后,他的启动时间是很长的,以本项目为例,首次运行时间为214秒,第二次启动时间就变成了96秒。这一切都得益于cache-loader
,他会帮我们缓存很多内容,第二次运行就会直接读取,而不是重新编译加载。
cache-loader
当你尝试修改vue.config.js
后缓存会失效,所以每次调整配置文件都会经历一段漫长的时间。下文中为了更普适,使用的是第二次的启动时间。
赛前准备
问题发现
打包日志输出的速度还是很快的,单凭肉眼是无法分辨的,所以这里借助了Camtasia
软件,他集录屏与查看功能为一体,可以做到按帧去分析,大家也可以尝试其他录屏方案,主流的视频软件都是支持按帧去查看的。有了这一神器,就可以开始分析打包日志了。
实际
问题分析
好了,现在我们根据发现的问题去优化项目。
其中一个最明显的问题就是,当执行npm run dev
之后,有一个阶段大概要占据10+s的时间,截图如下:
要知道,我这是在本地开发环境中,无论从哪方面论,都是不需要进行压缩的。遇到这个问题后我最初考虑到的是vue-cli
是不是有默认压缩的操作,为此我自己从零搭建了一个vue-cli
项目,并没有发现这个步骤,所以,肯定是vue.config.js
中的某些配置,为此我一条一条的筛查,最终定位到了为了优化项目首屏加载效率而添加的compression-webpack-plugin
,有的朋友可能会很好奇,这不够明显吗?是的,当局者迷的原因就是当时引入的方式,我是这么引入的,我以为已经判断了启动的环境:
const CompressionWebpackPlugin = require('compression-webpack-plugin');
module.exports = {
plugins: [
new CompressionWebpackPlugin(process.env.NODE_ENV !== 'development' ?{
// filename: "[path].gz[query]",
algorithm: "gzip",
test: new RegExp('\\.(' + ['js','css'].join('|') + ')$'),
threshold: 10240,
minRatio: 0.8
}: {}),
],
}
细心的朋友可能发现了问题,这里判断环境的语句是在plugin
内部的,换言之,无论是哪个环境,都会进行压缩操作,只是压缩的参数是否按照列举出来的进行压缩,所以我及时调整了压缩插件的添加方式,代码如下:
const CompressionWebpackPlugin = require('compression-webpack-plugin');
module.exports = {
chainWebpack (config) {
if (process.env.NODE_ENV === 'production') {
config.plugin('compressionPlugin')
.use(
new CompressionWebpackPlugin({
// filename: "[path][base].gz[query]",
algorithm: "gzip",
test: new RegExp('\\.(' + ['js','css'].join('|') + ')$'),
threshold: 10240,
minRatio: 0.8
}),
)
}
}
}
现在我们来看一下本地启动的时间:
不错,有了10秒的
优势,要知道,每次修改编译都是10秒节省,真是一笔可观的财富。
如问题发现环节的图所示:项目打包过程中使用了thread-loader
,在漫长的打包过程中频繁的会出现thread-loader
的身影,这个loader的作用是Runs the following loaders in a worker pool.
也就是将此loader放在其他loader
前,放置了这个loader
之后的loader就会在一个单独的worker
池中运行,从而加速打包过程。
我们项目的用法是在vue.config.js中添加:
configureWebpack: {
...//other code
module: {
rules: [
{
test: /\.js$/,
use: ['thread-loader']
}
]
},
...//other code
}
通过vue inspect > output.js
命令,可以发现,他自己单独作为一个loader出现,并没有与其他loader产生效应,为此,我们先删掉此loader看一下效果。
em…本来是加速打包进程的loader,删掉之后反而快了10秒,好,我们按照理解的方式重新加入到项目中:
configureWebpack: {
...//other code
config.module.rule('js').test(/\.m?jsx?$/).use('thread-loader').before('cache-loader').loader('thread-loader').options({
workers: 4,
// 默认为 20
workerParallelJobs: 50,
}).end()
config.module.rule('vue').test( /\.vue$/).use('thread-loader').before('cache-loader').loader('thread-loader').options({
workers: 4,
// 默认为 20
workerParallelJobs: 50,
}).end()
...//other code
}
基于上述逻辑,我分别尝试了几种情况下的第一次和第二次打包时间,具体情况如下(可根据实际情况调整参数):
不使用thread-loader
: 189秒,第二次加载77秒。
使用thread-loader
对babel-loader
进行加成:187秒,第二次加载77秒。
使用thread-loader
对babel-loader和vue-loader
进行加成:185秒,第二次加载76秒。
上面同等情况下,对第二次加载速度也没有明显的提升,大概稳定在77秒左右,所以上面的结论是,thread-loader也是要根据项目的实际情况选择,并不一定安装了thread-loader
一定会更快。大家可以根据实际项目的情况进行选择,其他配置可以参考thread-loader。
说到最后
通过上面的修改,确实节约了不少打包时间,解决的思路跟大家分享一下,如果有更好的建议,欢迎留言,共同进步!