后台系统静态资源加载优化实践

前言

因为这系统之前一直在不断迭代,现在暂时告一段落了,我赶紧趁着开年工作不多的空余时间,把这个系统优化一下,不然我可能就被优化了。

优化做啥

说到优化,网上一查一大堆教你的方法,要说的话,人人都能说两句,但是做的话不一定人人都能做好。那么我们该如何运用这些知识呢?

本系统基本情况:

  • 构建工具 vite4
  • 框架 vue3
  • UI组件库 tdesign
  • 公司内部业务组件库 sutpc-charts-utils

要优化,我们首先要知道有没有问题,问题自查的途径有很多,我这里用了浏览器自带的lighthouse,得到初步结果如下

自查结果1.png
自查结果2.png

不同的系统优化关注点不一样,由于我这个系统是一个后台系统,我这里主要关注性能,也就是图中的Performance的得分51的那部分,再一看这几个指标 如 FCP\ TTI \ LCP,一看就知道不太ok了,时间都4、5秒了,再看看网络资源加载方面:


网络.png

响应标头.png

根据经验一看就会发现有的js\css存在体积过大,而且都没有gzip压缩导致加载时间比较长的问题,同时,lighthouse也有对应的诊断,以及对应的改善建议

诊断、改善建议.png

如下图,点开第一条建议,果不其然,是让你开启资源压缩,压缩方法有:gzip,deflate或者brotli,我们用常用的gzip即可,它一般压缩率在70%左右。


第一条建议.png

然后再看看其他优化建议,包括

  • 减少未使用的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'],
          }
        }
      }
    },
分割前.png
分割后.png

看出来,优化前后主要变化是一个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

然后测试一下发现个问题,如下图


gzip开启的问题.png

好家伙!资源加载更慢了!如下图,随便点开某个请求一看原来是服务器响应慢,可能是啥原因呢?

耗时.png

是服务端自己的问题,仔细看了一下nginx配置找到了问题 :gzip_comp_level 5

改一下nginx配置, 把 gzip_comp_level 5改成 gzip_comp_level 2,因为level越高越占用cpu资源,现在改低应该可以把服务响应耗时短一点

    gzip_comp_level 2;
gzip_comp_level 2.png

看起来 “请求-响应” 时间确实从平均1.3s 降低到 700ms左右,约有4、50%的提升

优化完了,重新从lighthouse测试看一下成果


优化后1.png
优化后2.png

从效果上来看,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的文件返回。


压缩.png
gzip压缩后.png
指标得分.png

重新部署查看网络瀑布流,发现从请求耗时从700ms降低到100ms左右,提速明显,但是lighthouse重新测试发现 FCP \ LCP \ SI 指标得分并没有提升多少,Performance总得分也还是70多,这就奇怪了,从官方的建议来看,现在应该是GOOD阶段范围了

LCP scope.png

点击LCP指标下方的“查看原始追踪记录”按钮,进去查看:

原始追踪记录.png

从图中可以看到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条建议

  1. 减少未使用的js\css
  2. 考虑内联脚本样式
  3. 推迟所有非关键js\css


    剩下建议.png

    5、增大代码覆盖率
    其实要减少未使用的代码,我们得先了解一个概念:代码有个指标是代码覆盖率;代码覆盖率 = 使用的部分 / 全部;代码覆盖率越大说明你的代码用到的刀刃上的越多,而不是下载一大堆,只用一小部分功能。比如你引入了整个loadsh,只用到了深拷贝功能,其他没用到的功能代码也被打包部署,导致用户请求资源时浪费带宽,浪费时间,阻塞渲染。


    view Treemap.png

    代码覆盖率.png

根据上图的代码覆盖率来看,图中底部的表格中Coverage列里面的柱子,其中红色的部分表示是未使用的,所以我这里还是需要继续代码瘦身,把不用到的部分剔除。而且大头是前面两个js,体积大,而未使用部分又占比大。根据上文列举的剩下的3条优化建议,内联脚本样式不太现实,所以按照建议去

  1. 减少未使用的js\css
  2. 推迟所有非关键js\css

我的具体做法就是 把在main.ts全量引入sutpc-charts-utils这个组件库的代码删掉,改成在局部页面去按需引入具体的组件、配合defineAsyncComponent异步组件实现按需加载,也就实现了“减少未使用的js\css、推迟所有非关键js\css”

main.ts变化.png

局部页面异步方式按需引入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暂时不变,没改按需引入。

按需引入后打包.png

最后再部署测试一次 , Performance 90+分,FCP \ SI \ LCP \ TTI 几乎进入秒级!
最后测试结果.png

总结

本次优化主要是通过移除未使用的代码、代码分割、gzip压缩设置、按需引入等手段,降低了首屏资源请求时的“请求-响应”时间,从而达到资源加载优化的目的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容