前言
因为这系统之前一直在不断迭代,现在暂时告一段落了,我赶紧趁着开年工作不多的空余时间,把这个系统优化一下,不然我可能就被优化了。
优化做啥
说到优化,网上一查一大堆教你的方法,要说的话,人人都能说两句,但是做的话不一定人人都能做好。那么我们该如何运用这些知识呢?
本系统基本情况:
- 构建工具 vite4
- 框架 vue3
- UI组件库 tdesign
- 公司内部业务组件库 sutpc-charts-utils
要优化,我们首先要知道有没有问题,问题自查的途径有很多,我这里用了浏览器自带的lighthouse,得到初步结果如下
不同的系统优化关注点不一样,由于我这个系统是一个后台系统,我这里主要关注性能,也就是图中的Performance的得分51的那部分,再一看这几个指标 如 FCP\ TTI \ LCP,一看就知道不太ok了,时间都4、5秒了,再看看网络资源加载方面:
根据经验一看就会发现有的js\css存在体积过大,而且都没有gzip压缩导致加载时间比较长的问题,同时,lighthouse也有对应的诊断,以及对应的改善建议
如下图,点开第一条建议,果不其然,是让你开启资源压缩,压缩方法有:gzip,deflate或者brotli,我们用常用的gzip即可,它一般压缩率在70%左右。
然后再看看其他优化建议,包括
- 减少未使用的JavaScript并延迟加载脚本,直到需要它们, 来减少网络活动消耗的字节数
- 资源正在阻止页面的第一次绘制。考虑内联交付关键JS/CSS,并推迟所有非关键JS/样式
- 减少未使用的css
- 使用http2代替目前的http1.1
- 使用高效的缓存策略为静态资产提供服务
- 避免昂贵的dom操作
还有一些其他小建议就不一 一列举了
由于本系统的资源都在同一个域名(IP)下,且http协议是1.1版本, 所以会有最多6个TCP连接同时创建的限制。其实最好的办法还是上http2, 但是这又要先上https证书才行,考虑到这系统公司暂时不可能花钱搞这个证书,所以http2的想法就算了。
最后,根据现有问题、优化建议和实际情况,我打算做 代码瘦身、打包时的代码分割、gzip压缩、设置合适的缓存策略
具体操作:
1、移除未使用的插件,检查代码发现有一些插件如vue3-lazy
vue3-clipboard
没用到,删掉
2、配置代码分割
vite默认node_modules的非公用依赖全给你打到一个vendor.js里面去,导致的问题就是太大加载慢,所以需要分割,方便并行加载。方法就是自定义打包策略,如下例子,把非源码的依赖单独提取出来,再配合强缓存策略。
build: {
rollupOptions: {
output: {
manualChunks: {
'sutpc-charts-utils': ['sutpc-charts-utils'],
'vue-vendor': ['vue', 'vue-router', 'pinia'],
tdesign: ['tdesign-vue-next'],
}
}
}
},
看出来,优化前后主要变化是一个3366kb的chunk变成 两个, 分别是1037kb \ 2464kb , 在依赖不多的情况下,优化效果不大,至于其他的小chunk块变化不大。
3、配置gzip
让运维帮忙配置一下nginx,开启gzip
gzip on;
gzip_disable "msie6";
gzip_min_length 1024;
gzip_buffers 4 16k;
gzip_vary on;
gzip_comp_level 5;
gzip_static on;
gzip_types text/plain text/css application/json application/javascript
然后测试一下发现个问题,如下图
好家伙!资源加载更慢了!如下图,随便点开某个请求一看原来是服务器响应慢,可能是啥原因呢?
是服务端自己的问题,仔细看了一下nginx配置找到了问题 :gzip_comp_level 5
改一下nginx配置, 把 gzip_comp_level 5
改成 gzip_comp_level 2
,因为level越高越占用cpu资源,现在改低应该可以把服务响应耗时短一点
gzip_comp_level 2;
看起来 “请求-响应” 时间确实从平均1.3s 降低到 700ms左右,约有4、50%的提升
优化完了,重新从lighthouse测试看一下成果
从效果上来看,Performance从51 到 78分,几个相关指标时间也进入了2s左右,感觉效果还行。
能不能再快点?
从上面的几个关键资源加载情况来看,基本都要700ms左右,能不能再快点的?其实是可以的。因为上面的nginx的gzip设置都是实时压缩的,就是说每次请求资源,服务器都要把该文件压缩完再返回,这里是存在浪费时间的,由于这些静态资源每次打包生成之后就不会变化了,我们可以直接把它压缩好,这样子请求时直接把压缩好的资源返回就行了,省去每次请求都去压缩的时间开销,网络io就会更快!怎么做呢?装个压缩插件即可。
pnpm i vite-plugin-compression2 -D
vite.config.js配置
import { compression } from 'vite-plugin-compression2'
plugins: [
...其他插件
compression({
threshold: 1024,
include: [/\.css$/, /\.js$/]
})
],
上面配置对只对打包后大于1k的css、 js压缩,发现会多了一份后缀名是.gz的文件,然后把dist目录部署到服务上,nginx响应这些资源请求时会直接把对应.gz的文件返回。
重新部署查看网络瀑布流,发现从请求耗时从700ms降低到100ms左右,提速明显,但是lighthouse重新测试发现 FCP \ LCP \ SI 指标得分并没有提升多少,Performance总得分也还是70多,这就奇怪了,从官方的建议来看,现在应该是GOOD阶段范围了
点击LCP指标下方的“查看原始追踪记录”按钮,进去查看:
从图中可以看到LCP也就在1.2s左右的位置,哪里是lighthouse写的2.2s ? 不知道它是怎么算的,你知道吗?欢迎留言讨论。
4、 静态资源设置强缓存、协商缓存
在我另外一篇文章《彻底弄懂强缓存与协商缓存》说过缓存的原理,这里直接用上结论:index.html设置协商缓存,其他的设置强缓存。由于我这环境的nginx默认是有协商缓存的,所以我只配置需要强缓存的资源,如下,js|css|png|jpg 等资源强缓存30天,即2628000秒
location ~.*\.(js|css|png|jpg)$ {
add_header Cache-Control "max-age=2628000, private";
}
设置这些缓存只是对二次打开页面有用,对第一次打开测试效果没意义。截止目前来看最大的问题还是代码问题,如下最新的测试结果,查看优化建议如下图所示只剩下 3条建议
- 减少未使用的js\css
- 考虑内联脚本样式
-
推迟所有非关键js\css
5、增大代码覆盖率
其实要减少未使用的代码,我们得先了解一个概念:代码有个指标是代码覆盖率;代码覆盖率 = 使用的部分 / 全部;代码覆盖率越大说明你的代码用到的刀刃上的越多,而不是下载一大堆,只用一小部分功能。比如你引入了整个loadsh,只用到了深拷贝功能,其他没用到的功能代码也被打包部署,导致用户请求资源时浪费带宽,浪费时间,阻塞渲染。
根据上图的代码覆盖率来看,图中底部的表格中Coverage列里面的柱子,其中红色的部分表示是未使用的,所以我这里还是需要继续代码瘦身,把不用到的部分剔除。而且大头是前面两个js,体积大,而未使用部分又占比大。根据上文列举的剩下的3条优化建议,内联脚本样式不太现实,所以按照建议去
- 减少未使用的js\css
- 推迟所有非关键js\css
我的具体做法就是 把在main.ts全量引入sutpc-charts-utils这个组件库的代码删掉,改成在局部页面去按需引入具体的组件、配合defineAsyncComponent
异步组件实现按需加载,也就实现了“减少未使用的js\css、推迟所有非关键js\css”。
局部页面异步方式按需引入MatrixEditor组件的例子
const MatrixEditor = defineAsyncComponent(() => import('sutpc-charts-utils/dist/matrix-editor').then(({MatrixEditor}) => MatrixEditor))
import 'sutpc-charts-utils/dist/matrix-editor/style.css';
export default defineComponent({
render(){
return <div>
<MatrixEditor />
</div>
}
})
再次打包,发现原来最大的chunk: sutpc-charts-utils-[hash].js没了, 多了几个几百k的js,因为这些独立组件本来就比较大。至于tdesign-[hash].js暂时不变,没改按需引入。
最后再部署测试一次 , Performance 90+分,FCP \ SI \ LCP \ TTI 几乎进入秒级!
总结
本次优化主要是通过移除未使用的代码、代码分割、gzip压缩设置、按需引入等手段,降低了首屏资源请求时的“请求-响应”时间,从而达到资源加载优化的目的。