Vue 首頁秒開實(shí)踐指南
一
前端性能優(yōu)化一直是衡量一個(gè)團(tuán)隊(duì)和一個(gè)前端的各方面水平,呈現(xiàn)快速的加載,是給人最直觀,成就感也最足的一個(gè)感受,而且對(duì)用戶體驗(yàn)是第一重要的概念,所以這個(gè)相當(dāng)重要,現(xiàn)就來結(jié)合美團(tuán)的實(shí)踐方案來討論一下。
以下一段轉(zhuǎn)載自:美團(tuán)技術(shù)團(tuán)隊(duì)分享
自JavaScript誕生以來,前端技術(shù)發(fā)展非常迅速。移動(dòng)端白屏優(yōu)化是前端界面體驗(yàn)的一個(gè)重要優(yōu)化方向,Web 前端誕生了 SSR 、CSR、預(yù)渲染等技術(shù)。前端服務(wù)端渲染、后端服務(wù)端渲染等。
在美團(tuán)支付的前端技術(shù)體系里,通過預(yù)渲染提升網(wǎng)頁優(yōu)化,從而優(yōu)化了白屏問題,提升用戶體驗(yàn),并形成了最佳實(shí)踐。
在前端渲染領(lǐng)域,主要有以下幾種方式可供選擇:

通過對(duì)比,同構(gòu)方案集合 CSR 與 SSR 的優(yōu)點(diǎn),可以適用于大部分業(yè)務(wù)場(chǎng)景。
結(jié)合到我們團(tuán)隊(duì)負(fù)責(zé)的支付業(yè)務(wù)場(chǎng)景里,在保證系統(tǒng)穩(wěn)定性的前提下,還需要保障用戶體驗(yàn),所以采用了預(yù)渲染的方式。
那么究竟什么是預(yù)渲染呢?我們先從最常見的 CSR 開始說起。
以 Vue 舉例,常見的 CSR 形式如下:

一切看似很美好。然而,作為以用戶體驗(yàn)為首要目標(biāo)的我們發(fā)現(xiàn)了一個(gè)體驗(yàn)問題:首屏白屏(SPA都會(huì)遇到的問題)。
為什么會(huì)首屏白屏
瀏覽器渲染包含 HTML 解析、DOM 樹構(gòu)建、CSSOM 構(gòu)建、JavaScript 解析、布局、繪制等等,大致如下圖所示:

要搞清楚為什么會(huì)有白屏,就需要利用這個(gè)理論基礎(chǔ)來對(duì)實(shí)際項(xiàng)目進(jìn)行具體分析。通過 DevTools 進(jìn)行分析:

等待 HTML 文檔返回,此時(shí)處于白屏狀態(tài)。
對(duì) HTML 文檔解析完成后進(jìn)行首屏渲染,因?yàn)轫?xiàng)目中對(duì)加了灰色的背景色,因此呈現(xiàn)出
灰屏。
進(jìn)行文件加載、JS 解析等過程,導(dǎo)致界面長(zhǎng)時(shí)間出于灰屏中。
當(dāng) Vue 實(shí)例觸發(fā)了 mounted 后,界面顯示出大體框架。
由此得出,因?yàn)橐却募虞d、CSSOM 構(gòu)建、JS 解析等過程,而這些過程比較耗時(shí),導(dǎo)致用戶會(huì)長(zhǎng)時(shí)間出于不可交互的首屏灰白屏狀態(tài),從而給用戶一種網(wǎng)頁很“慢”的感覺。
二
優(yōu)化思路
在User-centric Performance Metrics一文中,共提到了4個(gè)頁面渲染的關(guān)鍵指標(biāo):

基于這個(gè)理論基礎(chǔ),再回過頭來看看之前項(xiàng)目的實(shí)際表現(xiàn):

可見在 FP 的灰白屏界面停留了很長(zhǎng)時(shí)間,用戶不清楚網(wǎng)站是否有在正常加載,用戶體驗(yàn)很差。
通過對(duì)比 FP、FCP、FMP 這三個(gè)時(shí)期 DOM 的差異,發(fā)現(xiàn)區(qū)別在于:



FP:僅有一個(gè) div 根節(jié)點(diǎn)。
FCP:包含頁面的基本框架,但沒有數(shù)據(jù)內(nèi)容。
FMP:包含頁面所有元素及數(shù)據(jù)。
仍然以 Vue 為例, 在其生命周期中,mounted 對(duì)應(yīng)的是 FCP,updated 對(duì)應(yīng)的是 FMP。那么具體應(yīng)該使用哪個(gè)生命周期的 HTML 結(jié)構(gòu)呢?

通過以上的對(duì)比,最終選擇在 mounted 時(shí)觸發(fā)構(gòu)建時(shí)預(yù)渲染。
三
構(gòu)建時(shí)預(yù)渲染方案
構(gòu)建時(shí)預(yù)渲染流程:

配置讀取
由于 SPA 可以由多個(gè)路由構(gòu)成,需要根據(jù)業(yè)務(wù)場(chǎng)景決定哪些路由需要用到預(yù)渲染。因此這里的配置文件主要是用于告知編譯器需要進(jìn)行預(yù)渲染的路由。
在我們的系統(tǒng)架構(gòu)里,腳手架是基于 Webpack 自研的,在此基礎(chǔ)上可以自定義自動(dòng)化構(gòu)建任務(wù)和配置。

觸發(fā)構(gòu)建
項(xiàng)目中主要是使用 TypeScript,利用 TS 的裝飾器,我們封裝了統(tǒng)一的預(yù)渲染構(gòu)建的鉤子方法,從而只用一行代碼即可完成構(gòu)建時(shí)預(yù)渲染的觸發(fā)。
TS的裝飾器:

使用:

為了提高構(gòu)建效率,并行對(duì)配置的多個(gè)頁面或路由進(jìn)行預(yù)渲染構(gòu)建,保證在 5S 內(nèi)即可完成構(gòu)建,流程圖如下:

四
我們梳理一下簡(jiǎn)化后的項(xiàng)目上線過程:
開發(fā) -> 編譯 -> 上線
構(gòu)建時(shí)預(yù)渲染研發(fā)流程及效果
最終,構(gòu)建時(shí)預(yù)渲染研發(fā)流程如下:

開發(fā)階段:
通過 TypeScript 的裝飾器單行引入預(yù)渲染構(gòu)建觸發(fā)的方法。
發(fā)布前修改編譯構(gòu)建的配置文件。
發(fā)布階段:
先進(jìn)行常規(guī)的項(xiàng)目構(gòu)建。
若有預(yù)渲染相關(guān)配置,則觸發(fā)預(yù)渲染構(gòu)建。
通過預(yù)渲染得到最終的文件,并完成發(fā)布上線動(dòng)作。
完整的用戶請(qǐng)求路徑如下:

通過構(gòu)建時(shí)預(yù)渲染在項(xiàng)目中的使用,F(xiàn)CP 的時(shí)間相比之前減少了 75%。

從此我們?cè)僖膊皇艿谝黄梁苈睦_了。并且可行性很好,也可以讓其他有需求的一起實(shí)踐。
??愛心三連擊 1.看到這里了就點(diǎn)個(gè)在看支持下吧,你的「點(diǎn)贊,在看」是我創(chuàng)作的動(dòng)力。
2.關(guān)注公眾號(hào)
程序員成長(zhǎng)指北,回復(fù)「1」加入高級(jí)前端交流群!「在這里有好多 前端?開發(fā)者,會(huì)討論 前端?知識(shí),互相學(xué)習(xí)」!3.也可添加微信【ikoala520】,一起成長(zhǎng)。
“在看轉(zhuǎn)發(fā)”是最大的支持
