前端頁面熱更新實現方案

本文作者:雅X共賞

原文鏈接:前端頁面熱更新實現方案

前端頁面熱更新

了解過前端性能優化的同學應該清楚,給頁面載入提速的終極方案就是CDN,這是BS架構本身的特點決定的,無論什麼前端提速手段,最終都會回到客戶端文件的傳輸上來;與之相對的CS架構則不存在載入壓力,但CS架構的問題是更新不靈活,那麼有沒有一種方法能結合這兩種架構的優點,在載入速度和更新靈活性之間找到一個平衡點呢?這就是本文要探討的一種方案:前端熱更新。

方案概述

「前端」和「熱更新」這兩個詞通常很少一起出現,提到熱更新一般都是指APP的一種靜默更新方式,這種方式會在用戶使用時悄悄檢測並下載增量更新包,當用戶下次打開APP時自動應用更新,從而將APP「更新」這個破壞連貫性的動作隱藏於無形;前端頁面的載入則相當於每次都是「全量更新」,如果能讓前端頁面也能用上「本地模板」,那將極大縮短前端載入時間,而且以此為前提,我們也可以實現一個前端的模板熱更新機制,做到不影響頁面更新的實時性。

應用場景

場景一:APP內嵌頁面。

比如電商類APP的首頁,經常需要改版或者做活動皮膚,如何減少更新成本就成了一個大問題。使用了熱更新方案我們就可以用HTML實現APP首頁,頁面內容以模板的形式存進localStorage,後台靜默更新模板,下次啟動自動生效;針對具有一定時效性的活動皮膚,我們以補丁的形式發布,補丁文件疊加在模板上產生最終的活動模板效果,對於補丁包我們可以提前載入並預存在本地,補丁包應該包含自身的生效時段信息,前端檢測到時間處於活動周期內時應用補丁。最終可以做到熱更新頁面無論改版還是做活動,只需要前端發版就可以,完全不需要APP端參與。

場景二:追求載入速度的web頁面。

對於web頁面來說更新不是問題,載入才是最大的問題,如果個別頁面希望極致提升頁面展現速度,那麼也可以使用該方案作為提速手段,但因為頁面的所有代碼都將存進localStorage,所以不適合大範圍使用。

需求細化

綜合以上場景和需求,最終我們要做的東西是一個「殼」頁面,該頁面沒有具體業務內容,只實現熱更新功能,每次載入都先檢查localStorage中是否存在模板,如果有則立即應用模板,此時頁面展現出來,如果沒有則進入下一步;下一步頁面會請求模板管理介面獲取最新模板信息,拿到模板信息後如果本地已有模板,則與本地模板比對版本信息,如果版本一致說明緩存命中,流程結束;如果本地版本不是最新,則獲取最新模板並存進本地,下次頁面載入時將應用最新的模板,流程結束;另一種情況是首次載入本地沒有任何模板,那麼將獲取最新模板,保存到本地,然後應用模板,流程結束。

前面說的是穩定模板的更新流程,穩定模板流程結束後會進入補丁模板更新流程。首先仍然是檢查本地是否存在補丁模板,如果已存在則檢測當前時間是否匹配補丁的生效時段,匹配則應用補丁,不匹配將進入下一步;下一步將獲取最新補丁模板並存到本地,然後檢測當前時間是否匹配最新補丁的生效時段,如果匹配則應用模板,不匹配流程結束。

完整流程如圖所示:

實現細節

介面數據

根據功能需求我們需要介面返回穩定模板信息和活動模板信息,分別都包含id和url兩個欄位,id用於版本校驗,url指向模板文件下載地址,活動模板信息還需要額外提供cycle欄位,定義活動模板的生效時段,與之相對的我們還需要介面返回伺服器當前時間,用於匹配活動模板的生效時段,最終完整的數據結構如下:

{ "status": "Y", "data": { "stableVersion": { "id": "17", "url": "" }, "activeVersion": { "id": "18", "url": "", "cycle": "2018,02,01-2018,02,10" }, "today": "2018,02,06" }}

本地數據

保存到本地的數據大致跟介面數據保持一致,只保留stableVersion和activeVersion信息,欄位在id和url基礎上再增加template用於保存模板字元串,完整本地數據結構如下:

{ "stableVersion": { "id": "17", "url": "", "template": "" }, "activeVersion": { "id": "18", "url": "", "cycle": "2018,02,01-2018,02,10", "template": "" }}

模板文件

前端頁面由三種語言構成,但我們希望只用一次請求就把模板文件拿到,所以模板是一個包含了html/css/js的文本文件,標籤格式就保持普通HTML文件的寫法,考慮到模板應用部分的實現,需要約定一下標籤的寫法,例如css必須用<style></style>標籤包裹,js必須用<script stylex="text/javascript"></script>標籤包裹,這樣一來用正則表達式就很容易提取到各部分代碼段。

模板應用

如上段所說,獲得模板文件後可以使用正則表達式拿到三種語言代碼,然後只需要按照css > html > js的順序依次將他們插入頁面相應位置,就完成了模板應用,唯一不同的是html代碼將以innerHTML的方式覆蓋進body元素。在應用順序上,將css放在html之前是為了避免重繪,將js放在html之後是為了能夠在js中操作DOM。

活動模板雖然定義為補丁,但模板構成跟穩定模板其實是相同的,應用方式也完全相同,只不過由於活動模板在穩定模板之後應用,所以活動模板的css和js都將以補丁的方式影響頁面,對於普通的換皮膚需求只需要css和js就足夠了,但如果希望html也能發生一些改變,根據html的覆蓋式應用方式,活動模板中就需要給出一份完整的html代碼,以達到修改html的目的。

效果展示

refined-x.com/WEB-OTA/ (二維碼自動識別)

後記

整個方案的流程比較瑣碎,但實現過程其實很簡單,部署成本也不高,只需要後端把模板管理起來,再提供一個更新介面就行了,但這套更新機制還是有一個小問題,那就是當有新版本發布時用戶並不能第一時間看到新版本,必須下次訪問才能更新到新版本,這算是靜默更新要付出的一點點代價吧,如果實在介意這個問題其實也容易解決,只需要在檢測到遠程有新版本時提示用戶重啟/刷新就可以了。

相比較HTML5的manifest緩存方案,我認為靈活性要更高一些,但不足之處在於不支持靜態文件的碎片化管理,但擴展這個功能也不複雜,無非模板信息里再擴展幾個欄位而已。

代碼在這裡了,更細節的東西自己看代碼吧.


由IMWeb核心成員操刀的前端NEXT學位課程第五期招生即將結束!

感興趣的小夥伴快點擊這裡,了解課程詳情吧!

更多乾貨與福利請關注公眾號【騰訊NEXT學位】!


推薦閱讀:

如今es8都出了 ,還有必要用ts嗎?
如何解讀Facebook的這款疑似Virtual DOM專利?
什麼樣的前端才是大公司要的前端?
React源碼(一) setState
組件化必殺技:styled-components 簡明教程【附視頻下載】

TAG:前端開發 | 前端入門 | 前端框架 |