PWA 漸進(jìn)式:你需要先搞懂這些

我們想要怎樣的 Web App?

文末有彩蛋

Web 頁(yè)面尤其是動(dòng)態(tài) Web 頁(yè)面和 Web App 的區(qū)別非常模糊, 但為了更清晰地討論 SPA、PWA 這些技術(shù)方案,還是先來(lái)定性地分析一下 Web App 背后的產(chǎn)品需求

平滑的、不被打斷的交互體驗(yàn)。如果交互過(guò)程中,頁(yè)面重新加載而丟失狀態(tài)、網(wǎng)絡(luò)原因使得頁(yè)面無(wú)法顯示,這樣用戶體驗(yàn)就會(huì)被打斷,就不夠 App。

與設(shè)備相適應(yīng)的布局。例如在移動(dòng)瀏覽器中展示 PC 頁(yè)面的完整布局,就會(huì)使用戶需要縮放和拖動(dòng)才能查看信息,就不是 App 的體驗(yàn)。

快速的呈現(xiàn)和響應(yīng)。進(jìn)入每一頁(yè)都需要漫長(zhǎng)的等待,或者用戶操作后得不到立即反饋,可能是 Web 頁(yè)面常見(jiàn)的問(wèn)題。

符合移動(dòng)端的交互習(xí)慣。移動(dòng)端特有的硬件使其 Native API 更加豐富,例如藍(lán)牙、二維碼、相機(jī)、支付、手勢(shì)滑動(dòng)、手勢(shì)縮放、觸感反饋等。

以上是筆者對(duì) Web App 需求的理解(歡迎留下評(píng)論),下文基于此展開(kāi)討論。

Web 架構(gòu)的優(yōu)勢(shì)

值得思考的是,即使 Web 頁(yè)面與我們對(duì)移動(dòng) App 的需求相差甚遠(yuǎn), Web 技術(shù)仍然是當(dāng)前移動(dòng) App 的架構(gòu)中必備的組成部分。我們依賴 Web 技術(shù)的地方正是 Web 架構(gòu)的優(yōu)勢(shì):

可鏈接。Web 在技術(shù)分類(lèi)上屬于分布式文檔,這些文檔通過(guò) URL 相互鏈接。無(wú)論是單個(gè)網(wǎng)站內(nèi)的不同頁(yè)面還是跨網(wǎng)站的頁(yè)面之間,都可以直接打開(kāi)而無(wú)需下載安裝。這里要強(qiáng)調(diào)一個(gè)隱含的功能:Deep Linking,即從一個(gè) App 跳轉(zhuǎn)進(jìn)入另一個(gè) App 內(nèi)的指定頁(yè)面,甚至還可以定位到特定的瀏覽位置。

可訪問(wèn)。HTML 是 Web 的基石之一,一方面提供了內(nèi)容和樣式的分離,使得機(jī)器和人都可以閱讀也便于開(kāi)發(fā)更復(fù)雜的樣式和交互;另一方面統(tǒng)一的標(biāo)記語(yǔ)言有更好的可訪問(wèn)性,這是其他平臺(tái)很難建設(shè)的,比如可以選擇和復(fù)制,盲人可以啟用屏幕閱讀器,甚至可以找命令行中查看一個(gè) Web 頁(yè)面。

零門(mén)檻。你不需要任何許可或付費(fèi)就可以參與開(kāi)發(fā)和提供 Web 服務(wù)。這意味著同時(shí)存在無(wú)數(shù)種方式來(lái)開(kāi)發(fā)一個(gè)網(wǎng)站,在一定程度上促成了 Web 技術(shù)的繁榮。

獨(dú)立部署。不同的 Web 服務(wù)之間,甚至同一 Web 服務(wù)的各部分,都可以獨(dú)立地部署和演化。新舊網(wǎng)站可以同時(shí)運(yùn)行在這一平臺(tái)上,這一點(diǎn)也是 HTML5 標(biāo)準(zhǔn)的迭代原則。

健壯性。Web頁(yè)面擁有分布式系統(tǒng)特有的健壯性。Web頁(yè)面和它所依賴的圖片、視頻、腳本、樣式等資源沒(méi)有硬性依賴:一方面部分資源掛掉頁(yè)面的其他功能仍然可用;另一方面Web App可以一邊下載一邊執(zhí)行,這是其他平臺(tái)很難具有的健壯性。

在 SPA 大行其道之后廣泛討論的兼容性、響應(yīng)式設(shè)計(jì)、可訪問(wèn)性(或稱無(wú)障礙)、頁(yè)面性能等問(wèn)題, 本來(lái)都是 Web 體系結(jié)構(gòu)的優(yōu)勢(shì),這是一個(gè)略帶調(diào)侃的示例頁(yè)面:https://motherfuckingwebsite.com/ 這個(gè)只有 81 行的網(wǎng)頁(yè),不僅傳遞了相當(dāng)多的內(nèi)容;而且它在兼容性、響應(yīng)式設(shè)計(jì)、可訪問(wèn)性、頁(yè)面性能方面都表現(xiàn)優(yōu)異。重要的是這個(gè)頁(yè)面使用的技術(shù)都來(lái)自Web早期,換句話說(shuō)這些非功能需求正是 Web 與生俱來(lái)的優(yōu)勢(shì)。既然我們正在費(fèi)力解決的這些問(wèn)題不來(lái)自于 Web 本身,那么這些問(wèn)題到底來(lái)自哪里?是重 JavaScript 框架的問(wèn)題,還是組件化方案的問(wèn)題,還是掉進(jìn)開(kāi)發(fā)者體驗(yàn)陷阱?

SPA 方案的困難

本文不去討論某個(gè)具體的 SPA 框架的成敗或優(yōu)缺點(diǎn),只討論采用 SPA 方案來(lái)實(shí)現(xiàn)我們想要的 Web App 存在哪些困難,以及 SPA 方案對(duì)既有 Web 頁(yè)面的影響。下面列舉 SPA 方案對(duì)架構(gòu)產(chǎn)生的一些比較重要的影響,從可鏈接性(URL)、可訪問(wèn)性,服務(wù)的獨(dú)立性等方面具體分析。

SPA 是一組高度耦合的頁(yè)面(頁(yè)面耦合)

SPA 方案要求 App 內(nèi)所有頁(yè)面位于同一服務(wù)實(shí)例上, 也就是說(shuō)處理 SPA 頁(yè)面請(qǐng)求的每個(gè)實(shí)例都必須擁有 App 內(nèi)所有頁(yè)面的信息, 這一信息通常是頁(yè)面組件的聲明。

這是因?yàn)?SPA 要求頁(yè)面切換不發(fā)生瀏覽器跳轉(zhuǎn)。設(shè)想操作流程『打開(kāi)頁(yè)面A -> pushState 到頁(yè)面 B -> 刷新 -> 返回』,這時(shí)瀏覽器不會(huì)重新加載 A,而只是觸發(fā) popstate 事件給 B。因此對(duì)于任意頁(yè)面 A,點(diǎn)出到的任意頁(yè)面 B,B 頁(yè)面反過(guò)來(lái)都需要 A 的信息,當(dāng)然頁(yè)面 A 也知道頁(yè)面 B 的信息,因此任意兩個(gè)有跳轉(zhuǎn)關(guān)系的頁(yè)面,都需要相互了解對(duì)方的信息,或引用對(duì)方組件。

這樣相互耦合的一組頁(yè)面,就構(gòu)成了一個(gè) SPA 方案的 Web App。這樣的 App 內(nèi)所有頁(yè)面都不再能夠『獨(dú)立部署』,因此也不能獨(dú)立迭代演化。這往往意味著它們的開(kāi)發(fā)調(diào)試、前端編譯、部署過(guò)程都是耦合在一起的, 這些都是 SPA 方案帶來(lái)的成本:

開(kāi)發(fā)依賴:因?yàn)橐軌虼蜷_(kāi)一個(gè)頁(yè)面必須引用對(duì)應(yīng)的組件,這些組件在開(kāi)發(fā)和調(diào)試階段一定需要綁在一起。如果兩個(gè)頁(yè)面涉及到業(yè)務(wù)會(huì)跨團(tuán)隊(duì),無(wú)疑會(huì)增加很多成本。

編譯依賴:考慮使用 MD5 戳的編譯方法,相互引用的一組文件必須一起編譯上線,這會(huì)降低協(xié)作效率因?yàn)樗鼈儽緦儆诓煌臉I(yè)務(wù)或團(tuán)隊(duì)。當(dāng)然也可以不使用 MD5 戳并分別上線,動(dòng)態(tài)調(diào)整引用關(guān)系,這樣的問(wèn)題在于無(wú)法平衡 HTTP 緩存和快速生效的矛盾。

此外,由于瀏覽器的同源策略,一個(gè) Web App 被限制共享一個(gè)域名。否則在富交互的場(chǎng)景下跨域?qū)?huì)是一個(gè)非常復(fù)雜的問(wèn)題, 當(dāng)然如果你愿意使用 JSONP 這么不安全的接口另當(dāng)別論。

強(qiáng)組件化容易陷入技術(shù)豎井(技術(shù)封閉)

SPA 方案伴隨著強(qiáng)組件化方案,容易陷入封閉的技術(shù)豎井。換句話說(shuō)就是容易一條路走到黑,失去 Web 應(yīng)有的架構(gòu)優(yōu)勢(shì)。這是因?yàn)楫惒巾?yè)面擁有異步的天性。瀏覽器重新渲染一個(gè)頁(yè)面時(shí), 全局變量、定時(shí)器、事件監(jiān)聽(tīng)器都會(huì)初始化為全新的,這是『刷新』的含義。而異步頁(yè)面卻不然:

異步頁(yè)面間,全局變量、定時(shí)器是共享的,沒(méi)有托管很容易亂掉。

異步頁(yè)面的?<script>?之間,執(zhí)行順序是不保證的,沒(méi)有托管極易出錯(cuò)。

因此絕大多數(shù) SPA 方案都不會(huì)讓你直接插入?<script>?來(lái)編寫(xiě)業(yè)務(wù)代碼, 與此相反,會(huì)提供類(lèi)似 模塊、組件 之類(lèi)的概念來(lái)托管一切。你可能需要存儲(chǔ)、需要網(wǎng)絡(luò)、需要路由、需要通信,你需要把所有 Web API 都封裝一遍。

這是各種 SPA 框架全家桶背后的邏輯。最終業(yè)務(wù)的運(yùn)行環(huán)境不再是瀏覽器,而是這套組件化方案。而社區(qū)的組件化方案不會(huì)像 Web 標(biāo)準(zhǔn)一樣去迭代,也不一定向下兼容,這在版本升級(jí)或框架遷移時(shí)會(huì)產(chǎn)生非常大的成本。

URL 不再能定位資源(URL 弱化,可訪問(wèn)性差)

對(duì)于原始 Web 頁(yè)面,URL 不僅能定位資源的頁(yè)面,甚至還能定位到頁(yè)面種的具體瀏覽位置。但是在 SPA 里頁(yè)面由 SPA 框架渲染,經(jīng)典的配置是對(duì)于所有 URL 都返回同一個(gè)資源, 瀏覽器端腳本通過(guò)?location.href?渲染不同的頁(yè)面。所以這有啥問(wèn)題?

首屏性能差。瀏覽器端渲染,在頁(yè)面下載過(guò)程中是白屏的;瀏覽器直接渲染頁(yè)面是流式的,下載多少渲染多少。

機(jī)器不可讀。搜索引擎、CLI 用戶代理等不支持腳本的用戶代理無(wú)法解析頁(yè)面,因?yàn)椴煌?URL 頁(yè)面內(nèi)容是一樣的。

無(wú)法定位瀏覽位置。因?yàn)闉g覽器不再托管整頁(yè)渲染也無(wú)法記錄和恢復(fù)瀏覽位置。

可以看到不僅鏈接(URL)的概念被弱化,而且可訪問(wèn)性天生就很差。比較先進(jìn)的 SPA 框架會(huì)提供服務(wù)器端渲染(SSR)來(lái)補(bǔ)救,但對(duì)架構(gòu)有額外的要求:前后端都可以進(jìn)行頁(yè)面渲染,通常會(huì)要求前后端同構(gòu)。

既然瀏覽器不再記錄瀏覽位置,就需要 SPA 框架來(lái)實(shí)現(xiàn)。但由于 Web App 內(nèi)可以局部地渲染任何一塊內(nèi)容。頁(yè)面的概念在 SPA 中就變得很模糊, 而樹(shù)狀 DOM 結(jié)構(gòu)確實(shí)無(wú)法映射到線性的 URL 結(jié)構(gòu)(除非你打算繼續(xù)破壞 REST 把數(shù)據(jù)塞到 URL 里)。因此即使花費(fèi)大力氣去做,也無(wú)法實(shí)現(xiàn)完美的瀏覽位置記錄。

History API 不完備(體驗(yàn)不穩(wěn)定)

History API 是指瀏覽器提供的瀏覽歷史相關(guān)的 BOM API, 包括 pushState 方法,popstate 事件,history.state 屬性等。先不提在某些瀏覽器下 API 缺失的問(wèn)題,在當(dāng)前標(biāo)準(zhǔn)和主流瀏覽器如 Safari 和 Chrome 中的表現(xiàn)就有許多問(wèn)題。這些問(wèn)題會(huì)導(dǎo)致非常不穩(wěn)定的體驗(yàn),例如前進(jìn)后退無(wú)效,URL 與頁(yè)面內(nèi)容不對(duì)應(yīng)、甚至出現(xiàn)交互沒(méi)有響應(yīng)的情況??傊畬?duì)于一個(gè)追求極致體驗(yàn)的 Web App 來(lái)講是無(wú)法接受的。下面羅列一些筆者遇到過(guò)的:

同步渲染的頁(yè)面資源 加載會(huì)延遲 popstate 事件。這使得頁(yè)面未加載完時(shí)可以通過(guò) pushState 點(diǎn)出但無(wú)法返回。

PopStateEvent.state 總是等于?history.state。因此當(dāng) popstate 事件發(fā)生時(shí),誰(shuí)都無(wú)法獲取被 pop 出的 state,這讓 state 幾乎不可用。

popstate 事件處理函數(shù)中無(wú)法區(qū)分是前進(jìn)還是后退。考慮刷新頁(yè)面的場(chǎng)景不能只存儲(chǔ)為變量,只能存儲(chǔ)在?sessionStorage?中,但這是同步調(diào)用會(huì)增加路由的延遲,而且需要維護(hù)配額不是一個(gè)簡(jiǎn)單可靠的方案。

有些高端瀏覽器(比如某些華為內(nèi)置瀏覽器)history.state,但支持 pushState 和 popstate。

iOS 下所有瀏覽器中,設(shè)置 scrollRestoration 為?manual?會(huì)使得手勢(shì)返回時(shí)頁(yè)面卡 1s,這讓恢復(fù)瀏覽位置也不存在簡(jiǎn)單可靠的方案。

沒(méi)有 URL 變化事件。在 pushState/replaceState 時(shí)不會(huì)觸發(fā) popstate 事件。因此沒(méi)有統(tǒng)一的 URL 變化事件,通常需要一個(gè)路由工具來(lái)包裝這些不一致。

手勢(shì)前進(jìn)/返回的行為在標(biāo)準(zhǔn)中沒(méi)有定義。這意味著有些瀏覽器會(huì)做動(dòng)畫(huà),有些不會(huì)。因?yàn)檫@些動(dòng)畫(huà)沒(méi)有定義任何 API 所以 SPA 框架接管頁(yè)面切換動(dòng)畫(huà)無(wú)法保證一致的體驗(yàn)。

Referer 的語(yǔ)義不再是來(lái)源(日志錯(cuò)誤)

在 Web 時(shí)代,Referer HTTP Header 用來(lái)標(biāo)識(shí)一個(gè)請(qǐng)求的來(lái)源,主要用于日志、統(tǒng)計(jì)和緩存優(yōu)化。典型的 SPA 框架會(huì)破壞 Referer 的語(yǔ)義。

SPA 中頁(yè)面跳轉(zhuǎn)分兩種情況:一種是用戶與 DOM 交互由腳本 pushState 來(lái)改變 URL;另一種是用戶與瀏覽器交互比如前進(jìn)后退按鈕或手勢(shì),此時(shí)瀏覽器觸發(fā) popstate 事件 來(lái)通知腳本。對(duì)于后一種情況,popstate 事件發(fā)生時(shí)頁(yè)面 URL 已經(jīng)發(fā)生變化,此時(shí)才會(huì)通知到 SPA 框架載入下一頁(yè)內(nèi)容。因此這時(shí)發(fā)出的請(qǐng)求 Referer 頭的值一定?是當(dāng)前頁(yè)的 URL 而不是來(lái)源頁(yè)的 URL。

PWA 帶來(lái)的機(jī)會(huì)

還不了解 PWA 的同學(xué)建議先去閱讀筆者在 2017 年給的調(diào)研:PWA 初探:基本特性與標(biāo)準(zhǔn)現(xiàn)狀, 除了目前 PWA 已經(jīng)得到 所有主流瀏覽器 的支持外,其他內(nèi)容仍然有效。此外 Harttle Land 也在年初支持了 PWA,你現(xiàn)在就可以把它添加到桌面,或添加到主屏, 也可以離線瀏覽(比如現(xiàn)在切斷網(wǎng)絡(luò),刷新本頁(yè)面)。

PWA 一詞出自 Alex Russell 的 Progressive Web Apps: Escaping Tabs Without Losing Our Soul, 從這篇文章標(biāo)題也可以看到 PWA 的精髓:在實(shí)現(xiàn) App 體驗(yàn)的同時(shí)不丟失 Web 架構(gòu)的優(yōu)勢(shì)。因此可以規(guī)避上述 SPA 的問(wèn)題,同時(shí)能夠充分發(fā)揮 Web 的優(yōu)勢(shì)。

漸進(jìn)式改善

Progressive 是指 PWA 的構(gòu)建過(guò)程。構(gòu)成 PWA 的標(biāo)準(zhǔn)都來(lái)自 Web 技術(shù), 它們都是瀏覽器提供的、向下兼容的、沒(méi)有額外運(yùn)行時(shí)代價(jià)的技術(shù)。因此可以把任何現(xiàn)有的框架開(kāi)發(fā)的 Web 頁(yè)面改造成 PWA,而且與 SPA 方案不同, 沒(méi)有強(qiáng)組件化機(jī)制,因此不需要一把重構(gòu)可以逐步地遷移和改善。

性能的提升

PWA 對(duì)性能的提升主要靠 Service Worker,它是在傳統(tǒng)的 Client 和 Server 之間新增的一層。性能提升程度取決于這一層的具體策略。例如:

如果使用緩存優(yōu)先策略。加載時(shí)間必然明顯更短。但用戶可能看到過(guò)時(shí)的內(nèi)容。

如果使用網(wǎng)絡(luò)優(yōu)先策略。加載時(shí)間必然更長(zhǎng),因?yàn)樵黾恿祟~外的緩存查詢時(shí)間。

當(dāng)然還可以應(yīng)用 Race 策略,總之性能如何取決于我們?cè)鯓涌刂?。PWA 使得我們有機(jī)會(huì)來(lái)定制這個(gè)策略,當(dāng)然是值得探索的。

體驗(yàn)的增強(qiáng)

PWA 方案更接近于 Web 的方式,它是 Web 的增強(qiáng)而不是替代。因此 Web 應(yīng)該有的交互體驗(yàn)會(huì)得到保證,此外 PWA 還提供了一些 App 方面的增強(qiáng)。具體地,相比于 SPA,PWA 可達(dá)到的體驗(yàn)效果主要表現(xiàn)在:

穩(wěn)定的交互反饋。頁(yè)面切換直接由瀏覽器托管,這就可以避免使用 history API,尤其是前進(jìn)后退等涉及瀏覽歷史棧的操作會(huì)更加穩(wěn)定,交互反饋也更加可預(yù)期。

離線可用。這或許是 PWA 最明顯的體驗(yàn)優(yōu)勢(shì),可以明顯提升媒體時(shí)長(zhǎng)和交互次數(shù)。

設(shè)備集成度更好。PWA 有一些新的瀏覽器能力,比如添加到桌面、推送通知等,是 SPA 所不具有的。

頁(yè)面瀏覽位置。相比 SPA 省去了龐大的實(shí)現(xiàn)代碼,但瀏覽位置保持卻更穩(wěn)定、更健壯。

PWA 的不足之處在于無(wú)法托管頁(yè)面切換,這一交互必須由瀏覽器實(shí)現(xiàn)。PWA 對(duì)速度的收益也需要額外說(shuō)明:如果既有系統(tǒng)可能已經(jīng)做過(guò)更激進(jìn)的優(yōu)化(例如此前已經(jīng)做過(guò)資源打包或本地存儲(chǔ)),

PWA 方案對(duì)加載時(shí)間可能并沒(méi)有提升,但對(duì)于 TTI 和真實(shí)用戶的感受應(yīng)當(dāng)有可感知的提升。因?yàn)?PWA 更接近瀏覽器容易理解的原始 Web 頁(yè)面,因此可以更好地利用瀏覽器優(yōu)化,比如 HTTP 緩存、文件為單位的編譯緩存等。

另一方面 PWA 方案的架構(gòu)更簡(jiǎn)單和解耦。長(zhǎng)期來(lái)看頁(yè)面傾向于比 SPA 體積更小,加載更快速。這方面建議多從架構(gòu)的長(zhǎng)期演化上考慮,見(jiàn)下一節(jié)的討論。

架構(gòu)上的優(yōu)勢(shì)

筆者更看好 PWA 是因?yàn)樗诩軜?gòu)上的優(yōu)勢(shì),這對(duì)軟件的迭代效率和長(zhǎng)期演化都有好處。選擇好的架構(gòu)可能沒(méi)有立竿見(jiàn)影的收益,但是卻會(huì)有利于軟件的演化和團(tuán)隊(duì)的發(fā)展,反過(guò)來(lái)也能更好地支持業(yè)務(wù)需求。

獨(dú)立部署和演化

PWA 方案不要求頁(yè)面組件之間存在引用關(guān)系,甚至不要求頁(yè)面之間有相同的組件抽象。這意味著頁(yè)面之間是解耦的。

因此服務(wù)/頁(yè)面仍然可以獨(dú)立部署和演化,不同的頁(yè)面仍然可以選擇適合自身業(yè)務(wù)的技術(shù)棧去開(kāi)發(fā)。不僅可以減輕團(tuán)隊(duì)管理的復(fù)雜度,也有利于各業(yè)務(wù)線的迭代效率。

業(yè)務(wù)開(kāi)發(fā)更加輕量

為了應(yīng)付日漸龐大的 Web 頁(yè)面,經(jīng)過(guò)優(yōu)化的 JavaScript 引擎已經(jīng)可以和一些編譯語(yǔ)言的速度相提并論。但今天的 Web 頁(yè)面腳本都大的離譜,龐大的腳本不僅會(huì)影響加載速度,過(guò)度依賴腳本還會(huì)讓頁(yè)面的可訪問(wèn)性變得很差,交互也變得不可預(yù)期。

采用 PWA 方案有利于減小頁(yè)面體積,提升頁(yè)面的加載性能。比如省去了龐大的 SPA 框架,更重要的是頁(yè)面的解耦讓頁(yè)面開(kāi)發(fā)更加輕量。

更多可能性

Service Worker 使得除了客戶端、服務(wù)器、中間代理之外,還可以存在一層定制的策略。Service Worker 可以用于性能優(yōu)化,甚至實(shí)現(xiàn)客戶端容災(zāi)。這是 Web 體系結(jié)構(gòu)上新的架構(gòu)元素,可能大有所為。

架構(gòu)更加簡(jiǎn)單

對(duì)架構(gòu)而言,簡(jiǎn)單性是穩(wěn)定性的前提。充分利用瀏覽器和已有 Web 架構(gòu),能夠讓前端更加簡(jiǎn)單。

獲取簡(jiǎn)單性的關(guān)鍵在于不要和瀏覽器對(duì)著干,而是著力于改進(jìn)瀏覽器。使用 Web 的方式解決問(wèn)題,就仍然走在 Web 的道路上,就不會(huì)損失 Web 應(yīng)有的體驗(yàn)和架構(gòu)優(yōu)勢(shì)。

不去托管資源加載,把它完全交給瀏覽器,請(qǐng)求 Referer 也就自然不會(huì)錯(cuò)了。

不去操作瀏覽歷史,把頁(yè)面切換交互交給瀏覽器,不僅頁(yè)面間可以解耦,交互效果也更穩(wěn)定。

參與標(biāo)準(zhǔn)建設(shè)

對(duì)一個(gè)大型網(wǎng)站來(lái)講,無(wú)論是業(yè)界的 SPA 方案還是 PWA 系列技術(shù),都會(huì)存在不足和缺陷。重要的是這二者的改進(jìn)方式完全不同:

改進(jìn) SPA 方案往往意味著在 Web 前端(即瀏覽器端)建設(shè)更復(fù)雜的抽象和全站統(tǒng)一的組件化;

改進(jìn) PWA 方案則意味著從瀏覽器端入手,通過(guò)與端的協(xié)作來(lái)解決問(wèn)題,同時(shí)保持 Web 前端架構(gòu)的簡(jiǎn)單。

前端與瀏覽器端的協(xié)作在業(yè)界已經(jīng)有很完善的實(shí)踐方式, 包括興趣收集、準(zhǔn)入和評(píng)審等環(huán)節(jié)都有現(xiàn)成的方法。Web 前端和私有平臺(tái)(自有端)的協(xié)作也應(yīng)當(dāng)采用這樣的方式。不僅可以通過(guò)與標(biāo)準(zhǔn)化組織的協(xié)作來(lái)維持架構(gòu)的先進(jìn)性,也可以通過(guò)緊密的社區(qū)協(xié)作來(lái)確保技術(shù)的包容性, 這樣自有端才能有自己的技術(shù)生態(tài),也更容易融入標(biāo)準(zhǔn)的迭代。這也是私有平臺(tái)技術(shù)影響力的一個(gè)來(lái)源。

結(jié)論和建議

我們想要的只是一個(gè)快速的、流暢的、功能豐富的 Web App。SPA 方案和 PWA 方案的區(qū)別在于解決問(wèn)題的方式。

SPA 的思路是封裝一切,讓開(kāi)發(fā)者面向框架而非 Web 本身。架構(gòu)足夠復(fù)雜以至于沒(méi)有明顯的問(wèn)題。

PWA 是網(wǎng)頁(yè)的漸進(jìn)增強(qiáng),技術(shù)上是中立的讓開(kāi)發(fā)者仍然面對(duì) Web。架構(gòu)足夠簡(jiǎn)單以至于明顯沒(méi)有問(wèn)題。

SPA 的復(fù)雜性在于業(yè)務(wù)之間因?yàn)榭蚣芗夹g(shù)(尤其是組件化)而產(chǎn)生耦合, 技術(shù)棧深而且封閉,重 JavaScript 的頁(yè)面可訪問(wèn)性和穩(wěn)定性也會(huì)變差, 而且 JavaScript 框架替代瀏覽器托管頁(yè)面加載這樣新的交互方式, 也會(huì)在用戶交互、日志統(tǒng)計(jì)等方面產(chǎn)生誤差和麻煩。與此相反,PWA 概念涉及的技術(shù)是 Web 標(biāo)準(zhǔn)迭代的產(chǎn)物, 不強(qiáng)制任何組件模塊框架,可以在任何已有 Web 頁(yè)面上漸進(jìn)增強(qiáng), 也允許不同的業(yè)務(wù)可以獨(dú)立迭代,因此更容易產(chǎn)出體積小的、加載速度快的頁(yè)面。同時(shí)新的 Service Worker 技術(shù)也使 Web 架構(gòu)有更多的技術(shù)可能

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容