前端工程化之H5性能優化篇

圖片

導讀:從粗糙到精緻,從簡單到複雜,全球互聯網Web App(網頁應用)平均體積已增壓到1.6Mb,隨着音視頻等富媒體內容的流量池膨脹,終端設備上的用戶對網頁裝載速度尤爲敏感。頁面不能作到秒開,就會有大量用戶選擇離開。重視並改善網站性能,優化即時網頁裝載時間,加速即時網頁在瀏覽器平臺終端狀態展示,進而能夠帶來網站流量增加。
本文源自百度直播研發部,提出了前端漸進加強的頁面渲染方案,即「路由分離+預靜態化+WebView預建立」方案,來替代模板同步渲染方案,並採用工程化的方式將能力打包下沉賦能產品線。html

1、背景

在直播業務落地的場景中,構建打賞服務精神,創造風格多樣,使人難忘的運營活動形式,以知足目標用戶需求。進行有效的服務創新,保障H5服務品質,控制訪問性能,及時化解金主情緒爲商業價值,製造特效驚喜,流暢的用戶體驗,有利於贏得用戶對平臺的尊重,提高平臺品牌氣質:前端

1. 優化訪問體驗:優化H5首屏性能,圍繞提高用戶服務感覺和提高開發者工做效率進行創新,探索Web追趕原生的體驗創新;
2. 加速需求閉環:解決H5頁面路由與數據接口耦合的問題,實現H5服務自治,釋放業務對Web產品形態的旺盛需求;
3. 基礎設施建設:使用工程化手段沉澱公共通用的前端基礎設施,讓前端組織更敏捷的支持跨業務的人力調配,技術賦能更多產品線;react

圍繞以用戶爲中心的功能完善的體驗,以客戶爲中心的商業價值的轉化。提高H5服務品質,發揮現代瀏覽器潛能,賦能傳統Web新的解決方案。
歷史架構的緣由,H5頁面的加載過程是Server向Smarty模板注入json_encode後的接口主數據,響應給瀏覽器帶有頁面徹底JSON數據的頁面,而後在瀏覽器端執行JavaScript,最終Paint給用戶,流程以下圖:webpack


圖片△H5優化前的加載與渲染流程
圖片△H5首屏關鍵路徑耗時拆解git

兩個影響H5首屏內容(FCP,First Contentful Paint,首次內容繪製)的關鍵路徑爲:
1. 網絡耗時:依賴Server端數據查詢及模板編譯,當數據查詢慢時延遲了首字節到達(TTFB,Time To First Byte,首字節時間)。
2. 內核渲染耗時:依賴JavaScript執行讀取頁面主數據並生成徹底的DOM結構。
所以,咱們針對性地設計並實施了「路由分離+預靜態化+WebView預建立」的方案,改進後的頁面加載與渲染流程以下圖:github


圖片△H5優化後的加載與渲染流程
web

2、路由分離

路由分離以前H5頁面的URL由Server分配,前端負責編寫TPL模板產物,TPL與最終URL的對應關係在Server經過配置文件作映射,日益暴露出啓動開發慢,頁面後期維護交接溝通成本高的問題。 因此咱們但願頁面路由規範化,讓前端開發者自主控制頁面入口格式,讓後端開發者更專一於API接口數據邏輯。所以,咱們設計了前端路由分離方案,約定了頁面URL與頁面源代碼目錄映射關係,規則以下圖:
圖片△預約式URL路由規範
NGINX直接響應預靜態化的HTML文件,首字節到達不依賴數據查詢與模版編譯。
json

3、預靜態化

前端路由分離直接在NGINX代理層返回HTML文件,但沒有頁面徹底渲染須要的數據,在執行AJAX請求沒有返回以前,須要規避頁面一直處於白屏或全局loading狀態,提早FCP的時間。 咱們採用了預靜態化頁面的方案。預靜態化不像服務器渲染那樣即時編譯產出徹底靜態化的 HTML,它只在構建時爲了特定的路由生成特定的幾個靜態頁面,咱們能夠經過 webpack插件將一些特定頁面在編譯時就注入DOM結構,這樣作有幾個好處:第一縮短頁面白屏時間,第二相對於服務器端渲染節省雲基礎設施資源成本,第三輸出給搜索引擎爬取頁面通用內容。 結合實際應用場景和市面上主流的預靜態化方式,最終咱們開發了基於ReactDomServer原生的服務端渲染能力的webpack插件,提高預靜態化性能和效率。 經過webpack插件系統獲取每次構建的compilation上下文,經過html-webpack-plugin的before AssetTagGeneration hook獲取當前頁面bundle,afterTemplateExecution hook獲取當前頁面編譯後的模板HTML,經過eval執行bundle導出的整個頁面APP模塊,經過ReactDomServer對單頁應用的每一個路由產出APP HTML與模板HTML合併後落盤爲預靜態化的HTML。小程序

H5預靜態化調用序列以下:後端

圖片△H5預靜態化調用序列


頁面入口export APP:

module.exports = (locals) => Promise.resolve(locals.preRender({id: containerId, main: App}));


基於Node.js環境,建立JSDOM實例提供瀏覽器宿主環境,使用ReactDOMServer將組件渲染爲靜態HTML標記。使用自研的預靜態化webpack插件替換html-webpack-plugin,並不增長新的編譯階段。 Webpack插件與市面上主流的預靜態化方法作個對比,如基於無頭瀏覽器的、基於本地啓動HTTP Server、通用的靜態站點生成工具等。結果以下:


react-snap

prerender-spa-plugin

react-snapshot

prep

snapshotify

@baidu/html-webpack-pre-render-plugin

State

supported

supported

unsupported

unsupported

experimental

supported

DOM implementation

puppeteer

phantomjs-prebuilt

jsdom

nightmare

puppeteer

jsdom+implement

Load performance optimisation

+

-

-

-

+

-

Zero-configuration

+

-

+

-

+

+

Redux

+

-

+

-

-

+

Async components

+

-

-

-

+

-

Webpack code splitting

+

+

-

-

+

-

CSSStyleSheet.insertRule

+

-

-

-

+

+implement

blob urls

+

?

-

-

-

+implement

All browser features

+

-

-

?

+

+implement

Speed

slow

slow

fast

slow

slow

fast(real time)


結果以下:

綜合對比,咱們的預靜態化速度最優,可在開發階段實時看到預靜態化結果,所見即所得,方便研發調試,不須要增長新的編譯階段。
遵循儘量讓頁面骨架內容顯示最終內容的原則,產出預靜態化的HTML文件,對於展現用戶個性化內容的動態組件,仍須要等待一個AJAX請求的時間,這部分組件在執行AJAX請求沒有返回以前,咱們採用了組件級別的Skeleton方案,以保證首屏使用通用內容+動態組件骨架填充:


1. 靜態組件開發時定義公共部分state,填充頁面公共部份內容,代碼示例:

 this.state = {            // 預靜態化環境的標記(編譯階段預靜態化插件注入)            isPreRender: window.isPreRender,             // 頁面公共內容            rights: [ // 權益                {                    dataIndex: 'cameraAction',                    icon: require('../../../../assets/cashVideoActivity/ricon_1.png'),                    button: require('../../../../assets/cashVideoActivity/do_shoot.png'),                    text: <span className='dt-text'>億萬獎金,<br />全網最高!</span>,                    action: {}  // 經過 dataIndex 在接口數據裏獲取                }, {                    dataIndex: 'renzhengAction',                    icon: require('../../../../assets/cashVideoActivity/ricon_2.png'),                    button: require('../../../../assets/cashVideoActivity/do_auth.png'),                    text: <span className='dt-text'>加V認證,<br />十倍收益!</span>,                    action: {}                }            ]        };


2. 動態組件根據window.isPrerender標記作預靜態化環境與瀏覽器渲染環境兩種環境下的響應,代碼示例:

// 組件骨架可以使用 http://danilowoz.com/create-content-loader/ 在線生成import ContentLoader from 'react-content-loader';const GrowthCardLoader = props => (    <ContentLoader        uniquekey="growth-card-loader"        animate        height={68}        width={320}        speed={1}        primaryColor="#333"        secondaryColor="#333"        {...props}    >        <rect x="0" y="0" rx="10" ry="10" width="320" height="68" />    </ContentLoader>);// 組件環境響應核心邏輯{    window.isPreRender    ? (        <GrowthCardLoader        className="growth-card-swiper-slide-loader"/>       ): (        <正式組件 ...     )}


圖片△動態組件在兩種環境下的響應流程 通過預靜態化後的頁面首屏內容(FCP)不依賴JS執行完畢,經過一次首次渲染(FP,First Paint,首次繪製)便可向用戶展現出頁面公共內容,待AJAX返回後替換成徹底渲染的頁面。

4、WebView預建立

在APP啓動時當即初始化好WebView組成的緩存池,保證加載每一個URL時省去了WebView初始化的時間,並利用上預靜態化的HTML緩存,最終使頁面無白屏加載態。

5、總體收益

866f0ff06078e851c29eb91c52c4d367.png△優化效果可感知對比(左新右舊)
 

渲染流程改進先後對比:
圖片圖片△渲染流程改進先後對比

直接收益:
圖片△H5性能優化直接收益

預靜態化收益:
1. 發佈前端通用高性能預靜態化插件;2. 提供了工程化引入骨架屏(Skeleton)的方式。
路由分離收益:
1. 約定式的頁面URL路徑,減少維護成本,減小先後端溝通成本;2. BrowserRouter支持,針對SPA(Single Page Application)頁面場景,支持了基於history API的BrowserRouter訪問方式;3. 刪除模版配置管理步驟,對於後端同窗能夠更加專一於數據邏輯。

6、工程化


前端組織從小做坊發展到了大前端時代,前端工程開發模式受到了新的挑戰如模塊化、組件化、規範化、自動化等。
前端工程本質上是軟件工程的一種。軟件工程化關注的是性能、穩定性、可用性、可維護性等方面,注重基本的開發效率、運行效率的同時,思考維護效率。採用工程化的思想管理前端工程範疇的各環節,轉化挑戰爲機遇,建立支持多團隊協做的開發流,創建堅實的工業前端基礎設施。

7、總結

Web H5性能優化再也不是隻追求一兩個頁面裝載速度指標的提高,更考驗一個前端團隊的綜合能力:
1. 頂層設計能力在設計時提早佈局,尋找痛點一擊即中,並根據實際狀況不斷維護、進行調整、優化、保證規範有效性;
2. 工程管理能力用更有效的工做方法和手段使全局實踐最優,節約成本並提高研發效率;
3. 文化創新能力持續學習是最好的創新辦法,始終保持着與時俱進的基本價值觀,每一次契機均可能會促成一次成功的創新,創造獨特價值。
Web生態技術突飛猛進,性能是日趨規範化的領域,如PWA/快應用/小程序,標準化是完全解決頻發問題、改善工做質量的好辦法。

參考資料| https://github.com/stereobooster/react- snap/blob/master/doc/alternatives.md

推薦閱讀:https://mp.weixin.qq.com/s?__biz=Mzg5MjU0NTI5OQ==&mid=2247486548&idx=1&sn=bf787117618d7b075523c95ba1d1720c&chksm=c03d3c28f74ab53e8ed4d70b55047be9cb93ff211a3530270be1b78cdf5e16f4d6a44d940571&token=1567390415&lang=zh_CN#rd

推薦閱讀:

百億級流量的百度搜索中臺,是怎麼作可觀測性建設的?

十億級流量的搜索前端,是怎麼作架構升級的?

百度信息流和搜索業務中的彈性近線計算探索與應用


----------  END  ----------

百度架構師

百度官方技術公衆號上線啦!

技術乾貨 · 行業資訊 · 線上沙龍 · 行業大會

招聘信息 · 內推信息 · 技術書籍 · 百度周邊

相關文章
相關標籤/搜索