事情的起因是这样的:
鄙人呢,在公司负责一个小小的后台管理系统。
这天中午临近饭点的时候,测试小哥坐我工位旁边现场监督我改一个Bug。
Bug本身它倒是不复杂,甚至时隔几天之后我已不记清具体内容是什么。当时只见我是三下C两下V、提交、合并测试分支、登录Jekins点击deploy,一顿操作如行云流水一般丝滑。
说时迟,那时快。公司给极品廉价劳动力们我们安排的午饭送到了,一人一份。但你也知道,这两年经济下行,无人幸免;有的人食不果腹,有的人衣不蔽体,保不齐谁饿的紧,拿了两份饭,那可就意味着有一个人要饿肚子,我可万万不希望那个倒霉蛋是我。
看着Jekins的deploy进度条,我对测试小哥说:
“你先回去,等会发完了你再看一下,应该没有问题,我先去干饭了”
说罢,我转头看向测试小哥:他面无表情盯着屏幕,似乎是默许了我的提议。于是我便准备起身——
只见他头也不回一手把我按住,缓缓吐出四个字:
“看完再吃”
...
...
...
大约半个小时后,KFC。
我:“我都告诉你了,不会有问题,先干饭,你非不听”
测试小哥:“......”
我:“这下好了吧,上个月的工资还没发,现在又来付费上班”
测试小哥:“我就问你,星期四的这个辣翅,它香不香”
我:“香”
罪魁祸首
所以,项目到底deploy了多久?
Jekins的记录中可以看到,编译打包环节耗时基本在五六分钟,最近几次成功构建的整体耗时平均在5分50秒。
这个项目本身呢,说大不大,说小也不算小。是个普通CRUD
页面居多的管理后台,没有太多其他乱七八糟的东西。如果以页面、组件数量的维度来看:
使用资源管理器在项目的/src
目录下通配*.vue
可以看到有561个文件
说实话,这样的体量打包5-6分钟,属实有点过分。
我又找来公司的一个巨石应用来对比:由于巨石应用历史比较悠久,横跨了多个技术栈(HandleBars模板引擎、使用jQuery的原生HTML、Vue2),不能只看SFC
的数量,所以这次就来比较一下,用来存放页面文件的文件夹的体积。
我的项目
巨石应用
先不算其他的资源,单就页面文件体积已经接近5倍,如果其他东西都算上,打包时间就算没有5倍,一两倍总是要有的吧?
结果呢,时间甚至更短
好好好,有活干了。为了避免下次面试官问我对webpack做过什么优化时复述那些网上千篇一律的答案,现在就来实际操作一下。
本文真实记录了一次对项目构建耗时、产物体积优化的过程。没有对知识点系统的梳理,主要突出的是思路:面对问题时的解决思路。
日志分析
曾经有位技术能力超强的架构师说过:遇到问题不要慌,先看日志。
既然这么慢的构建过程是发生在Jekins上,那就先来捋一捋Jekins的log,有没有什么值得注意的地方。
这个项目的构建脚本中,抛开(Jekins)工具的准备、从git上拉取代码以及最后的部署这些动作,只看跟前端的打包有关的部分,命令很简单,只有四行:
rm -rf node_modules
rm package-lock.json
npm i
npm run build
在日志中体现如下图:
开局就是一记暴击!
11:22:08 + npm i
11:25:59 + added 1863 packages from 1199 contributors balabala...
...
...
11:25:59 + npm run build
...
...
合着这五六分钟的打包时间,安装依赖就占了一大半,阿西巴!
在继续往下进行之前,请允许我先介绍些项目的其他背景:
deploy脚本拉取代码这一步简单来说就是:cd进项目目录 -> git pull -> 切换至要构建的分支
项目的开发人员较少,算我在内三个人
项目的依赖变动频率十分低,以月或数月为单位
背景铺垫完了,开始研究npm i
为什么这么耗时,相关的命令有三句:
rm -rf node_modules
rm package-lock.json
npm i
其中npm i
这句是必须的,没什么好说的;rm -rf node_modules
和rm package-lock.json
这两句是变量,挨个做耗时的对比测试。
首先,我在本地使用跟Jekins上相同的node版本(14.16.1),使用相同的npm源(官方源),新建一个目录clone项目代码:
1.完整执行三行命令,耗时与Jekins上相差无几
2.(此时已经有了package-lock.json
文件)执行rm -rf node_modules
+ npm i
,耗时极短
3.(此时已经有了node_modules
目录)执行rm package-lock.json
+ npm i
,耗时也极短
第三步其实没什么意义,npm文档中有提到,这种情况就相当于梳理了node_modules的结构并生成了package-lock.json
,并没有安装任何东西。
而步骤一和步骤二之间为何耗时相差比较大,可以参考这篇我觉得npm install流程写的比较好的文章:简单来说就是花费了大量时间去远端获取包信息。
结合项目背景一,我们的package-lock.json
会提交到仓库,每次肯定都是最新的,所以Jekins deploy脚本中rm package-lock.json
这一步属实是没有必要,本地计算完了到Jekins上又来一遍,纯纯的浪费时间。
联系运维哥把测试环境的deploy脚本修改一下,去掉了rm package-lock.json
这一句,测试下耗时:
如图中下边两次构建,【编译打包】环节时间都去到了2分30秒左右,直接缩短了一半多。部署成功后,在测试环境的页面咔咔一顿点,似乎也没有什么依赖包引起的报错。
效果是不是很显著,你以为这就完了?不不不,图中那条49秒的构建我可不是大意截进去的,伪装成不经意的失误,就是为了丝滑的承上启下
既然这个项目的开发人员很少,而且依赖的添加/更新频率又极低,也就意味着每次npm i
所安装的东西,基本都是一样的,既然都一样,为什么我还要rm -rf node_modules
再安装?
想象一下你日常本地开发时,如果某次需求要用到一个新的npm包,你一定是先npm install xxx
,除非碰到了依赖冲突,否则不会清除node_moduels
重新安装。
明明npm
提供了梳理依赖树、只做局部更新的逻辑,我们却偏偏每次清除node_modules
再install
,这种行为吧,我感觉就像明明是个Vue
项目,却在里边到处使用Document API
。
哎嘿,我就不用你的响应式,就是玩~
冒着被打的风险又私聊了运维哥,把rm -rf node_modules
去掉,再发布了一次看看效果
优秀!打包时间从5分多直接干到了50秒,优化率80%+!
本文结束!
在正式结束前,觉得还是有必要补充两点
各位读者在做打包优化时,部署脚本是否清除
package-lock.json
和node_modules
还是主要取决于项目实际情况和团队协作模式,不能因为一味的追求构建速度而导致频繁的构建失败/安装依赖失败[滑稽]如果您经过深思熟虑后觉得还是有必要清除
package-lock.json
和node_modules
,山人还有一计可供大王优化构建速度:打包时离不开babel,但babel又是个老大难,好在它能缓存转换结果。一般情况下缓存会放在项目目录下的/node_modules/.cache/
,那我们把删除node_modules
的命令稍微改那么亿点:find node_modules/ -mindepth 1 -maxdepth 1 ! -name '.cache' -exec rm -rf {} +
删除
node_modules
里面除了/.cache
目录以外的其他内容,这样在构建过程中babel还是能使用到之前的缓存。那速度,体验过的都说好!(看babel-loader的缓存文件有多大)
全面升级
如果是本着以后不影响吃午饭的目的,那现在确实可以结束了。但我自幼便深受中国四大名句之一来都来了的兄弟句式——干都干了的文化熏陶:既然已经开始了,那就干脆给项目做个全套大保健!
不过此时我和在座的各位都一样,对打包优化这块着实没什么经验,可以说是毫无头绪。
浅浅百度了下webpack打包优化,有两个工具基本每篇文章都有提到:打包耗时分析speed-measure-webpack-plugin
、打包体积分析webpack-bundle-analyzer
(vue-cli内置)
目前的痛点是慢,那就先来个耗时分析试试水。
使用方法还是老样子,自己去查,别人都写的我就不再重复写了。
效果如图:
此时因为babel
和eslint
还没有缓存,耗时多是意料之中的;其他的loader或多或少的三两组合,展示了一个module计数和耗时小计,我从中并没有办法获得什么有用的信息;并且多次构建对比发现loader组合的规律和耗时的排名也无迹可寻。在我的认知里:所有被命中的文件会按照loader
配置的顺序依次处理,所以面对这样的结果我实在是无计可施。(有会看的朋友可以补充一下)
翻看speed-measure-webpack-plugin
的文档,发现有可以打印耗时top N文件的配置项,但开启后再次构建得到的这些文件,同样令我摸不着头脑:一个寥寥数十行的SFC
小组件,css-loader
耗时竟然能用四到五秒!要知道里边只有一条scoped
的样式规则。
无奈只好放弃,看了下项目用的是vue-cli@4.x
创建的,对应的webpack@4.x
,那就去webpack
的文档里逛逛碰碰运气吧!
可惜,福无双至祸不单行。文档里翻了半天,耳熟能详、配置简单的路子,例如babel-loader、eslint-loader的编译缓存
、多线程打包
、chunk分割
、代码混淆压缩
、tree shaking
这些,要么是之前已经被配置过了,要么是webpack
内置了。而复杂、高级一些的优化方式,我的项目又用不到...
直到我看到了这里:
升级webpack
简单(呸),npm upgrade webpack
嘛,先来搞这个~~
回到项目的package.json
里,咦,好奇怪,没有webpack
,也没有vue-cli
。
vue-cli
是装在全局的,而webpack
是作为依赖的依赖安装的,没有体现在package.json
中,所以直接npm upgrade webpack
应该是不行的。vue-cli
的文档提供了一个升级的命令:vue upgrade
既然要升级,干脆全上新的!Node
也给他干到20!(我也不知道我当时为什么要这么做,但这为后来的事情埋下了伏笔。。。)
vue-cli
升级完,扫了一遍webpack升级指南,发现我项目里的配置文件也没什么好改的,Nice!
本地浅浅的run了一下server
、run了一下build
,发现也都OK!那就提交上去在Jekins上试试Node V14
o不ok
emmmm...
报错倒是没报错,只是...
本地build
的时候没注意,Jekins上跑才发现,怎么慢了这么多!说好的更新到最新版本均有助于提高性能呢?
再看看这构建物的体积
Hà的我赶紧又本地build
了一次,还真让我发现了些东西:似乎build
了两次
按理来说应该只有下边这个print,那上边的legacy bundle
又是什么东西?百度上随便那么一搜,应该是不少人都被这么坑过,很容易搜到:这是一种兼容性的构建产物,主要是为了兼容一些很古老版本的浏览器/客户端。想控制也很容易,改package.json
里的browserslist
字段即可。
这就好办了,这项目是我们公司的内部项目,考虑兼容性?不存在的。
{
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
]
}
配置了之后又试了下,基本恢复到了升级webpack
之前的水平,但还是慢一点点..
构建速度的优化这块,实在是没头绪了,明明升级了webpack
版本,构建速度却变慢了。
不过刚才提到的两个工具,构建耗时分析的用过了,还有个vue-cli
内置的构建体积分析工具没体验;如果需要打包的东西变少了,那构建速度应该也能快一点吧!(吧?)
塑形瘦身
在正式瘦身前,有一个小插曲:
不知道在座的各位,项目里有没有这样的东西
console.log(123123)
// or
console.log('asdfasdf')
我是一个崇尚极简的人,我能接受的底线也就是
console.log('list data: ', data);
仅此而已
你要打印接口返回数据,Network
里能看
你要打印函数中某个变量的值,可以打断点
我实在是想不出什么必须console.log
的场景
如果你说为了方便线上调试
我能接受的最多也就是按规范打印有意义的log
更别提项目首屏就要翻好几页的无意义log,要知道,大量的console.log
也是会影响首屏加载性能的
在之前,我通过husky + lint-staged
进行过限制,但还是有人以我这个有用、这之前不是我写的等等诸多借口绕过了eslint
检测,提交了无意义的log。所以这次我最终还是决定,你不仁就休怪我不义,TerserPlugin
drop_console
走起,本地开发你随便log,只要发到线上我就删掉。
{
plugins: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
pure_funcs: ["console.log", "console.info"],
},
},
})
]
}
毕竟删掉几句console.log
,也算瘦身
________________________________________________
接着就webpack-bundle-analyzer
走起,vue-cli
内置的使用方式是
vue-cli-service build --report
打包后会在你输出的目录里边生成一个report.html
,当时的截图找不到了,用语言描述一下就是:从node_moduels
里打进去的依赖包,面积直接占了整个屏幕的大概三分之一。那个图网上很容易找到,内容就是打包产物按照体积和来源绘制成一个个的矩形在页面里。
这其实是好事,打进去的依赖包多,我们的可操作空间就大,先拿Vue
开个刀。
// vue.config.js
module.exports = {
// ...
configureWebpack: {
externals: {
vue: "Vue",
},
},
// ...
}
也不要忘了把package.json
里的vue
依赖删除掉、在/public
的模版HTML
中,通过<script>
引入CDN文件。
再打个包看看效果:
可以看到vue
确实咩有了
但在调试的过程中,发现第三方CDN不稳定,时而获取超时
为了保险起见,只得把CDN文件copy到本地/public
里来(我司没有自己的CDN或者依赖私仓,正在筹备中)
暂时没什么问题了,下一个就是我们的UI组件库ant-design-vue@1.7.8
,按照相同的方式配置一下,不过这次运行后有报错了:
可以看到报错是和moment
有关系,在antd的文档也找到了原因:如果使用已经构建好的文件,要自行引入moment
为什么antdv不做按需引入?原因有二:
项目的入口
main.js
中全量导入了antdv
进行注册,页面中直接使用。如果要改成按需引入,要么每个页面里新增按需引入的语句,要么统计使用了哪些组件在main.js
里改为按需引入(似乎有plugin解决这个问题,记不太清了)按需的这个需,基本等于全量了。。。粗略的扫了一下文档,除了像
Comment
和Mentions
这种带有互动性质的组件,其他的基本都用上了,所以改按需好像意义也不大
改moment
的时候国际化有一个小问题,CDN网站一般会提供以下几种文件:
无国际化的
moment
主体文件带全部语言包的
moment
主体文件单个语言包文件(无功能)
如果没有国际化的需求,那是万万没有必要引入全部语言包的moment
。但moment
默认是英语,至少需要引入一个中文语言包。碰巧antdv
也需要做国际化处理,是相同的问题。
moment
和antdv
的国际化方式很相似:
<a-config-provider :locale="antdLocale" />
moment.locale(momentLocale);
data() {
return {
antdLocale,
momentLocale
}
}
我们只需要知道这个locale
运行时的值,把它提取出来就行了。打印后发现其实就是个很简单的key-value
对象(不是JSON
),在node_modules
中的源码里找到 它们复制出来在/public
下新建zhCN
文件:
window.momentLocale = xxx /* 复制出来的对象 */
window.antdLocale = xxx /* 复制出来的对象 */
使用时:
<a-config-provider :locale="antdLocale" />
moment.locale(momentLocale);
data() {
return {
antdLocale: window.antdLocale,
momentLocale: window.momentLocale
}
}
以后如果有别的依赖也有类似的国际化需求,继续向zhCN.js
里添加就行。只需要新增一个http
请求,就解决了所有依赖的国际化问题。
剔除了antdv
和moment
之后的report.html
:
惊喜的发现,antdv
的icons
也被一起干掉了。
少了这么几个大家伙,此时必须要Jekins上build一波看看效果!
还记得之前把Node
给升到20了吗
于是就...报错了...Node
版本太低...
本地切回NodeV14
,发现连server
也起不来了。。
摸黑前行
预警:这将是一段枯燥且艰难的黑暗时光
搞过的都知道,处理Node
版本兼容问题时,如果是需要升级还好;如果是要降级,Node
内置的各种包会出现稀奇古怪的报错,而且这些报错还难以trace
...
由于这趴的问题实在过于稀奇,甚至在google上都搜不到有用的信息,所以基本都没有截图,但我会尽可能的描述出我对问题的看法。看文字也许你觉得云淡风轻解决起来很轻松,但实际上花费了我接近一整天的时间以及一撮撮掉落的头发...
npm run server
出现大量的.vue
单文件报错具体的报错信息记不太清,但报错顺序与路由表注册的顺序相符(和动态路由懒加载是两码事,路由懒加载是在运行时访问到页面才会加载对应的
chunk
,但编译打包时,只要是代码中webpack
能trace
到的文件,都会被处理)。目测是所有的.vue
都有报错,那问题就应该不是出在代码上,而是整体配置上。翻看
vue-loader
文档时看到了这个
升级vue-cli
时确实也升级了vue-loader
,按照指引配置了下,resolve
2. jsx语法报错
这个问题就有点奇怪了,在升级前,是没有给webpack
做过什么支持jsx
语法的配置的。升级后,却都报错了。
翻阅了一些资料和支持jsx
的解决方案,大部分都是说把SFC
的<script>
加上lang="jsx"
,里边的内容全部当作jsx
解析。这种方式对eslint
和babel
的配置改动比较大,曾数次尝试无法成功,最后都把所有配置还原重新开始。
后来灵光一闪,不如直接用刚更新的vue-cli
创建一个新项目,看是否支持,如果可行的话,直接把各个配置文件照搬即可
结果还真可以。babel.config.js
、vue.config.js
以及package.json
里eslintConfig
字段,先全部按照官方脚手架的配置改掉,成功启动之后再挨个把我们自定义的配置添加回去。这过程当中没有出现什么问题,且按下不表,resolve
3. 启动之后,页面白屏报错(0 , vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent) is not a function
其中resolveComponent
也有可能是其他一些Vue3
暴露出来的Api,通过打断点观察,推测是Vue
内部在初始化的时候出了问题。
不确定是哪里出了问题,但在把之前删除的Vue
依赖安装回来(只是开发环境会用到,打包不会打进去)以及把添加的VueLoaderPlugin
去掉以后,resolve
迎接黎明
以上这些问题解决以后,已经可以正常启动、打包项目了。但刚才的bundle analyzer
进行到一半还没结束,图中的第三方依赖库应该还有一些可以剔除掉的,比如隐藏在一个业务代码chunk
里的echarts
检索了代码后,发现有按需引入的:
import {xxx, xxx} from "echarts"
也有全量引入的:
import * as echarts from 'echarts';
在分析代码后整理了所使用到的echarts
Api和组件,把全量引入改为按需引入,重新打包后发现包体积没有变。我好奇难道echarts
只要有一个地方使用了按需引入,其他地方也能自动分析把全量引入改为按需引入?遂把按需引入的也反向改为全量引入重新打包,结果:
第二次的改动体积变化了,那就只能说明....
问了写那段代码的同事,果然,在需求迭代的过程当中技术方案变更了,所以那个文件废弃掉没有用了,改了个寂寞...
此时还剩下jquery
和lodash
计划剔除掉,其他的依赖包有一部分已经是比较规范的按需引入,剔除掉改为cdn引入带来的收益不大,当然主要的原因还是因为懒
jquery
:这个npm包有点意思
打进来的是非压缩版本,因为package.json
中设置的main
就确实是这个,但dist
包中明明提供了压缩后的版本。两个版本的体积差距在三倍多,不知包作者的意图是什么
但最后还是把jquery
这个依赖彻底放弃了:整个项目中只有一个远古时期添加的图片预览组件依赖了它,而我们现在开发了样式、功能更为强大的新组件,所以把所有使用到这个组件的地方都改为使用新组件,然后顺带把jquery uninstall
了。
lodash
:官网本身提供了可按需引入的版本lodash-es
,但项目中太多地方都是全量引入的方式在使用
import * as _ from "lodash"
暂且先改成CDN的方式全量引入
至此,bundle analyzer
的分析图变成了这样:
三方依赖的chunk
已经比包含了echarts
的那个业务代码chunk
体积还要小。瘦身瘦到这里感觉差不多了,那些更小的依赖包本身体积不大,换成一个http
请求也未必是一件划算的事。
然后就还是回到webpack
的配置上来,前边一直在琢磨怎么添加配置去做优化,但vue-cli
本身已经封装了一套久经考验的配置,不如从这个配置着手,看能否针对我们项目的实际情况做一些修改
获取配置命令(融合了自定义的配置)
vue inspect --mode=production > file-name.js
mode
不传的话默认是development
。下载下来打开,1400多行猛的一看似乎有点唬人,但实际上有1000行左右都是对样式文件的loader
配置。
粗略的看下vue-cli@5.0.8
中有哪些值得注意的配置
解析文件的优先级
// 导入模块时如果不提供文件后缀,同名文件 后缀名的优先级
extensions: [".mjs", ".js", ".jsx", ".vue", ".json", ".wasm"]
Hash
optimization: {
realContentHash: false, // 使用非严格的hash计算,减少耗时
}
代码压缩:
css
使用的是CssMinimizerPlugin
,js
使用的是TerserPlugin
minimizer: [
// 已经内置了js压缩工具terser
new TerserPlugin({
terserOptions: {
compress: {
arrows: false,
collapse_vars: false,
comparisons: false,
computed_props: false,
hoist_funs: false,
hoist_props: false,
hoist_vars: false,
inline: false,
loops: false,
negate_iife: false,
properties: false,
reduce_funcs: false,
reduce_vars: false,
switches: false,
toplevel: false,
typeofs: false,
booleans: true,
if_return: true,
sequences: true,
unused: true,
conditionals: true,
dead_code: true,
evaluate: true,
},
mangle: {
safari10: true, // 代码混淆时兼容使用`let`关键字声明的循环迭代器变量可能会出现无法重复声明let变量的错误。
},
},
parallel: true, // 多进程打包
extractComments: false, // 不将注释单独提取到一个文件中
}),
new CssMinimizerPlugin({
parallel: true,
minimizerOptions: {
preset: [
"default",
{
mergeLonghand: false,
cssDeclarationSorter: false,
},
],
},
}),
]
Loader
大量的篇幅编排不同样式文件相关的
Loader
,分别有css
、postcss
、scss
、sass
、less
、stylus
,按照css moduels in SFC
->SFC style
->normal css modules
->normal css
的顺序依次处理。对于脚本文件,已经开启了多线程转译以及babel缓存功能
{
test: /\.m?jsx?$/,
exclude: [
function () {
/* omitted long function */
},
],
use: [
{
loader:
"path-to-your-project/node_modules/thread-loader/dist/cjs.js",
},
{
loader:
"path-to-your-project/node_modules/babel-loader/lib/index.js",
options: {
cacheCompression: false,
cacheDirectory:
"path-to-your-project/node_modules/.cache/babel-loader",
cacheIdentifier: "1d489a9c",
},
},
],
}
Plugin
VueLoaderPlugin
:已经内置了DefinePlugin
:注入编译时的全局配置CaseSensitivePathsPlugin
:路径的大小写严格匹配FriendlyErrorsWebpackPlugin
:优化报错信息MiniCssExtractPlugin
HtmlWebpackPlugin
CopyPlugin
:配置了info.minimized = true
,copy的同时也会压缩ESLintWebpackPlugin
:同样开启了缓存
得,不仅没找到有啥可优化的地方,甚至还污染了人自带的配置:
已经内置了TerserPlugin
,前边为了打包时去除console
在plugin
里边又配置了一次,通过speed-measure-webpack-plugin
分析时发现似乎是走了两遍TerserPlugin
。
只好通过webpack-chain
去注入一下,顺便把项目中其他修改webpack
配置的地方也改为注入的形式。(使用ConfigureWebpack
去改,无法改到已有的TerserPlugin
配置):
chainWebpack: (config) => {
config.when(process.env.NODE_ENV === "production", (config) => {
config.devtool(false);
config.optimization.minimizer("terser").tap((args) => {
const compress = args[0].terserOptions.compress;
args[0].terserOptions.compress = {
...compress,
drop_console: true,
pure_funcs: ["console.log", "console.info"],
};
return args;
});
});
config
.externals({
vue: "Vue",
moment: "moment",
"moment/locale/zh-cn": "moment.local",
"ant-design-vue": "antd",
lodash: "_",
})
.resolve.alias
.set("@", path.join(__dirname, "src"))
.set("@worker", path.resolve(__dirname, "public/worker.js"))
.end();
config.plugin("speed-measure").use(SpeedMeasurePlugin);
}
},
如果使用ConfigureWebpack
:
configureWebpack: {
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
pure_funcs: ["console.log", "console.info"],
},
},
}),
],
集成的配置最下方会出现一个新的minimizer
数组,不是我们想要的效果
截止到目前,构建速度变成这样(果然还是没有变更快)
项目剔出去的第三方依赖,体积是这么多
不过虽然没打进chunk里去,但还是作为静态依赖在构建产物中,下一步就是搭一个公司内部的简易缓存服务器(有关缓存的内容可以看我上一篇文章)。届时这部分体积才算真正从项目里移除了,不过此时我们还是可以把它视作优化的成果,由于没有对别的类型的资源做什么优化处理,也压根就没什么别的资源,所以只看打包后的js体积的话:
优化前
优化后
数据也基本对的上,所以综合来看:
平均构建速度(average full time):从5分50秒减少到54秒,优化率84.48%(
1 - 54秒 / 3分50秒
)脚本构建体积(script size):从5.5M减少到3.6M,优化率35.55%(
1 - 3.6M / 5.5M
)
先这样吧,至少下次被问到webpack
,多少有点自己的东西能讲
欢迎真诚交流,但如果你来抬杠?阿,对对对~ 你说的都对~
l来源:https://juejin.cn/post/7389044903940603945