前言
因?yàn)檫@系統(tǒng)之前一直在不斷迭代,現(xiàn)在暫時(shí)告一段落了,我趕緊趁著開年工作不多的空余時(shí)間,把這個(gè)系統(tǒng)優(yōu)化一下,不然我可能就被優(yōu)化了。
優(yōu)化做啥
說到優(yōu)化,網(wǎng)上一查一大堆教你的方法,要說的話,人人都能說兩句,但是做的話不一定人人都能做好。那么我們該如何運(yùn)用這些知識呢?
本系統(tǒng)基本情況:
- 構(gòu)建工具 vite4
- 框架 vue3
- UI組件庫 tdesign
- 公司內(nèi)部業(yè)務(wù)組件庫 sutpc-charts-utils
要優(yōu)化,我們首先要知道有沒有問題,問題自查的途徑有很多,我這里用了瀏覽器自帶的lighthouse,得到初步結(jié)果如下


不同的系統(tǒng)優(yōu)化關(guān)注點(diǎn)不一樣,由于我這個(gè)系統(tǒng)是一個(gè)后臺系統(tǒng),我這里主要關(guān)注性能,也就是圖中的Performance的得分51的那部分,再一看這幾個(gè)指標(biāo) 如 FCP\ TTI \ LCP,一看就知道不太ok了,時(shí)間都4、5秒了,再看看網(wǎng)絡(luò)資源加載方面:


根據(jù)經(jīng)驗(yàn)一看就會(huì)發(fā)現(xiàn)有的js\css存在體積過大,而且都沒有g(shù)zip壓縮導(dǎo)致加載時(shí)間比較長的問題,同時(shí),lighthouse也有對應(yīng)的診斷,以及對應(yīng)的改善建議

如下圖,點(diǎn)開第一條建議,果不其然,是讓你開啟資源壓縮,壓縮方法有:gzip,deflate或者brotli,我們用常用的gzip即可,它一般壓縮率在70%左右。

然后再看看其他優(yōu)化建議,包括
- 減少未使用的JavaScript并延遲加載腳本,直到需要它們, 來減少網(wǎng)絡(luò)活動(dòng)消耗的字節(jié)數(shù)
- 資源正在阻止頁面的第一次繪制??紤]內(nèi)聯(lián)交付關(guān)鍵JS/CSS,并推遲所有非關(guān)鍵JS/樣式
- 減少未使用的css
- 使用http2代替目前的http1.1
- 使用高效的緩存策略為靜態(tài)資產(chǎn)提供服務(wù)
- 避免昂貴的dom操作
還有一些其他小建議就不一 一列舉了
由于本系統(tǒng)的資源都在同一個(gè)域名(IP)下,且http協(xié)議是1.1版本, 所以會(huì)有最多6個(gè)TCP連接同時(shí)創(chuàng)建的限制。其實(shí)最好的辦法還是上http2, 但是這又要先上https證書才行,考慮到這系統(tǒng)公司暫時(shí)不可能花錢搞這個(gè)證書,所以http2的想法就算了。
最后,根據(jù)現(xiàn)有問題、優(yōu)化建議和實(shí)際情況,我打算做 代碼瘦身、打包時(shí)的代碼分割、gzip壓縮、設(shè)置合適的緩存策略
具體操作:
1、移除未使用的插件,檢查代碼發(fā)現(xiàn)有一些插件如vue3-lazy vue3-clipboard沒用到,刪掉
2、配置代碼分割
vite默認(rèn)node_modules的非公用依賴全給你打到一個(gè)vendor.js里面去,導(dǎo)致的問題就是太大加載慢,所以需要分割,方便并行加載。方法就是自定義打包策略,如下例子,把非源碼的依賴單獨(dú)提取出來,再配合強(qiáng)緩存策略。
build: {
rollupOptions: {
output: {
manualChunks: {
'sutpc-charts-utils': ['sutpc-charts-utils'],
'vue-vendor': ['vue', 'vue-router', 'pinia'],
tdesign: ['tdesign-vue-next'],
}
}
}
},


看出來,優(yōu)化前后主要變化是一個(gè)3366kb的chunk變成 兩個(gè), 分別是1037kb \ 2464kb , 在依賴不多的情況下,優(yōu)化效果不大,至于其他的小chunk塊變化不大。
3、配置gzip
讓運(yùn)維幫忙配置一下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
然后測試一下發(fā)現(xiàn)個(gè)問題,如下圖

好家伙!資源加載更慢了!如下圖,隨便點(diǎn)開某個(gè)請求一看原來是服務(wù)器響應(yīng)慢,可能是啥原因呢?

是服務(wù)端自己的問題,仔細(xì)看了一下nginx配置找到了問題 :gzip_comp_level 5
改一下nginx配置, 把 gzip_comp_level 5改成 gzip_comp_level 2,因?yàn)閘evel越高越占用cpu資源,現(xiàn)在改低應(yīng)該可以把服務(wù)響應(yīng)耗時(shí)短一點(diǎn)
gzip_comp_level 2;

看起來 “請求-響應(yīng)” 時(shí)間確實(shí)從平均1.3s 降低到 700ms左右,約有4、50%的提升
優(yōu)化完了,重新從lighthouse測試看一下成果


從效果上來看,Performance從51 到 78分,幾個(gè)相關(guān)指標(biāo)時(shí)間也進(jìn)入了2s左右,感覺效果還行。
能不能再快點(diǎn)?
從上面的幾個(gè)關(guān)鍵資源加載情況來看,基本都要700ms左右,能不能再快點(diǎn)的?其實(shí)是可以的。因?yàn)樯厦娴膎ginx的gzip設(shè)置都是實(shí)時(shí)壓縮的,就是說每次請求資源,服務(wù)器都要把該文件壓縮完再返回,這里是存在浪費(fèi)時(shí)間的,由于這些靜態(tài)資源每次打包生成之后就不會(huì)變化了,我們可以直接把它壓縮好,這樣子請求時(shí)直接把壓縮好的資源返回就行了,省去每次請求都去壓縮的時(shí)間開銷,網(wǎng)絡(luò)io就會(huì)更快!怎么做呢?裝個(gè)壓縮插件即可。
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壓縮,發(fā)現(xiàn)會(huì)多了一份后綴名是.gz的文件,然后把dist目錄部署到服務(wù)上,nginx響應(yīng)這些資源請求時(shí)會(huì)直接把對應(yīng).gz的文件返回。



重新部署查看網(wǎng)絡(luò)瀑布流,發(fā)現(xiàn)從請求耗時(shí)從700ms降低到100ms左右,提速明顯,但是lighthouse重新測試發(fā)現(xiàn) FCP \ LCP \ SI 指標(biāo)得分并沒有提升多少,Performance總得分也還是70多,這就奇怪了,從官方的建議來看,現(xiàn)在應(yīng)該是GOOD階段范圍了

點(diǎn)擊LCP指標(biāo)下方的“查看原始追蹤記錄”按鈕,進(jìn)去查看:

從圖中可以看到LCP也就在1.2s左右的位置,哪里是lighthouse寫的2.2s ? 不知道它是怎么算的,你知道嗎?歡迎留言討論。
4、 靜態(tài)資源設(shè)置強(qiáng)緩存、協(xié)商緩存
在我另外一篇文章《徹底弄懂強(qiáng)緩存與協(xié)商緩存》說過緩存的原理,這里直接用上結(jié)論:index.html設(shè)置協(xié)商緩存,其他的設(shè)置強(qiáng)緩存。由于我這環(huán)境的nginx默認(rèn)是有協(xié)商緩存的,所以我只配置需要強(qiáng)緩存的資源,如下,js|css|png|jpg 等資源強(qiáng)緩存30天,即2628000秒
location ~.*\.(js|css|png|jpg)$ {
add_header Cache-Control "max-age=2628000, private";
}
設(shè)置這些緩存只是對二次打開頁面有用,對第一次打開測試效果沒意義。截止目前來看最大的問題還是代碼問題,如下最新的測試結(jié)果,查看優(yōu)化建議如下圖所示只剩下 3條建議
- 減少未使用的js\css
- 考慮內(nèi)聯(lián)腳本樣式
-
推遲所有非關(guān)鍵js\css
剩下建議.png
5、增大代碼覆蓋率
其實(shí)要減少未使用的代碼,我們得先了解一個(gè)概念:代碼有個(gè)指標(biāo)是代碼覆蓋率;代碼覆蓋率 = 使用的部分 / 全部;代碼覆蓋率越大說明你的代碼用到的刀刃上的越多,而不是下載一大堆,只用一小部分功能。比如你引入了整個(gè)loadsh,只用到了深拷貝功能,其他沒用到的功能代碼也被打包部署,導(dǎo)致用戶請求資源時(shí)浪費(fèi)帶寬,浪費(fèi)時(shí)間,阻塞渲染。
view Treemap.png
代碼覆蓋率.png
根據(jù)上圖的代碼覆蓋率來看,圖中底部的表格中Coverage列里面的柱子,其中紅色的部分表示是未使用的,所以我這里還是需要繼續(xù)代碼瘦身,把不用到的部分剔除。而且大頭是前面兩個(gè)js,體積大,而未使用部分又占比大。根據(jù)上文列舉的剩下的3條優(yōu)化建議,內(nèi)聯(lián)腳本樣式不太現(xiàn)實(shí),所以按照建議去
- 減少未使用的js\css
- 推遲所有非關(guān)鍵js\css
我的具體做法就是 把在main.ts全量引入sutpc-charts-utils這個(gè)組件庫的代碼刪掉,改成在局部頁面去按需引入具體的組件、配合defineAsyncComponent異步組件實(shí)現(xiàn)按需加載,也就實(shí)現(xiàn)了“減少未使用的js\css、推遲所有非關(guān)鍵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>
}
})
再次打包,發(fā)現(xiàn)原來最大的chunk: sutpc-charts-utils-[hash].js沒了, 多了幾個(gè)幾百k的js,因?yàn)檫@些獨(dú)立組件本來就比較大。至于tdesign-[hash].js暫時(shí)不變,沒改按需引入。

最后再部署測試一次 , Performance 90+分,F(xiàn)CP \ SI \ LCP \ TTI 幾乎進(jìn)入秒級!

總結(jié)
本次優(yōu)化主要是通過移除未使用的代碼、代碼分割、gzip壓縮設(shè)置、按需引入等手段,降低了首屏資源請求時(shí)的“請求-響應(yīng)”時(shí)間,從而達(dá)到資源加載優(yōu)化的目的。


