假如 Web 當初不支持動態化

假如 Web 當初不支持動態化
關注「前端向後」微信公衆號,你將收穫一系列「用心原創」的高質量技術文章,主題包括但不限於前端、Node.js以及服務端技術前端

楔子
Web 生而具備極其靈活的動態化基礎能力,諸如:小程序

  • 動態插入script標籤執行任意腳本邏輯後端

  • 動態插入style標籤引入任何 CSS 樣式規則瀏覽器

  • 經過iframe標籤嵌入整站服務器

  • 以上標籤都可直接加載網絡資源微信

  • 承載這些內容的 Web 頁面部署在遠程服務器,可隨時動態更新,而且能當即生效

一直以來的探索和實踐彷佛只是在不斷地發掘動態化能力的工程價值,爲其尋找更合適的應用場景,好比早期的frameset,現在的微前端/微應用網絡

而移動端正好相反,生而具備許多靈活性限制:app

  • 原生不支持動態執行邏輯代碼框架

  • 構成移動應用程序的關鍵資源大都要打入安裝包中(動態庫例外)異步

  • 應用程序安裝在用戶設備上,安裝包更新需經應用商店審覈,用戶從新安裝才能生效

移動業務的發展不斷地對動態化能力提出更高的要求,但苦於缺乏動態化的基礎能力,因此一直在探索更靈活的技術方案,像早期的熱修復/熱更新,到現在的小程序

實際上,兩者在動態化技術能力上所要解決的工程問題是一致的,好比動態加載依賴庫、視圖組件、甚至整個應用。因此不妨開個腦洞,假定 Web 不支持動態化,以 Native 的業務訴求來推演 Web 動態化技術的發展軌跡

伊始:原生 WebAssembly

0061 736d 0100 0000 0187 8080 8000 0160
027f 7f01 7f03 8280 8080 0001 0004 8480
8080 0001 7000 0005 8380 8080 0001 0001
0681 8080 8000 0007 9080 8080 0002 066d
656d 6f72 7902 0003 6763 6400 000a ab80
8080 0001 a580 8080 0001 017f 0240 2000
450d 0003 4020 0120 0022 026f 2100 2002
2101 2000 0d00 0b20 020f 0b20 010b

從前,Web 應用程序只能被打包成這種wasm的二進制格式,發佈到各大瀏覽器應用商店。期間,不只要等待數天的審覈,經過以後還要等用戶主動安裝更新,等到新版本真正「生效」(覆蓋大多數用戶),可能已是數月以後了

版本更迭慢,不管是戰略性的重要功能仍是十萬火急的問題修復,都沒法及時觸達用戶。即使線上着火了,最快速的救火方案也要幾天甚至幾周以後才能起到做用

爲了可以更快地修復問題、下降風險,熱修復方案的探索就此展開

浪花:爲熱修復引入腳本語言 JavaScript
熱修復意味着要加載並運行(安裝包以外的)邏輯代碼,因此有人直接從 WebAssembly 模塊加載機制入手,研究出了一些 Hook 方案,可以動態地換掉某些模塊/文件

也有人沿着這個方向走得更遠,權衡時效性、性能、兼容性與穩定性,經過編譯插樁、工程配套設施、運行時框架等手段解決了模塊依賴、版本管理、差量更新等問題,將應用程序的各個功能模塊插件化

還有人另闢蹊徑,引入輕量級的腳本語言運行時(如 JavaScript 引擎),並在瀏覽器原生 WebAssembly 與 JavaScript 世界之間架起一座橋樑,容許經過 JavaScript 調用原生的系統平臺能力,從而擴展出了動態化的基礎能力

動態化漾起了一道波紋,緊接着是呼嘯而來的動態更新浪潮

海嘯:基於 JavaScript 的動態更新
往動態化方向邁出第一步以後,離全面動態化的大好前景也就一步之遙了:

Any application that can be written in JavaScript, will eventually be written in JavaScript. —— Jeff Atwood

(摘自The Principle of Least Power)

全面動態化意味着要:

  • 將應用程序中全部可以動態化的部分全都遷由 JavaScript 實現

  • *將龐大的 JavaScript 代碼按功能模塊組織起來,並管理好功能模塊之間的依賴關係

從而實現以功能模塊爲單位的快速迭代,至關於將熱修復技術應用到問題修復以外的需求迭代上,既不用發版,免去了審覈週期,也不須要等待用戶主動安裝,新功能得以動態發佈並迅速覆蓋到活躍用戶

堤壩:容器概念造成

隨着動態化程度的不斷提高,JavaScript 在應用程序中的佔比愈來愈高,最終僅剩餘沒法動態化(或沒有必要動態化)的部分仍由 WebAssembly 實現,包括:

  • 系統平臺能力橋接

  • 基礎 UI 控件、交互能力

  • 視圖層框架(歷史棧管理、生命週期支持等)

  • 特定業務領域能力(例如多媒體內容生產、IM SDK 等)

  • 通訊機制(廣播、狀態共享等)

這些部分造成了容器(原生外殼),至關於運行在瀏覽器中的一個動態化運行時,在容器圈定的能力範圍內,業務可以充分利用動態優點,實現快速修復、快速發佈、快速觸達、快速迭代

但隨容器概念一同出現的,除了賦能業務跑得更快以外,還有動態業務與容器之間的依賴問題:

  • 如何解除兩者之間的強耦合,如路由、混合視圖容器等場景?

  • 如何識別出兩者之間的依賴關係?

  • 如何保障依賴關係是可控的,好比禁止將依賴新能力的動態業務發佈到舊容器中?

經過工程配套設施將依賴管束起來以後,接下來的首要問題是想辦法保證動態業務所依賴的底層容器的可靠性

邊界:HTML、JavaScript、CSS 構成容器標準
隔離變化的慣用手段是加一層抽象,將變化的部分置於抽象層之下:

  • BOM API:對系統平臺、視圖層框架能力以及通訊機制的抽象

  • Native Module API:對特定業務領域能力的抽象

  • DOM API:對基礎視圖渲染能力的抽象

  • JS API:對 JavaScript 運行時的抽象

  • CSS:對樣式、佈局能力的抽象

  • HTML:對基礎 UI 控件、交互能力的抽象

抽象出的這些標準確立了穩固的容器邊界,邊界以內,動態業務可以肆意發揮,邊界之下,容器一樣可以不斷精進、豐富容器能力,將邊界拓寬。同時,具備標準定義的 API 可以以結構化的形式維護起來,對於開發體驗大有裨益

雲海:瀏覽器支持加載網絡資源
另外一方面,在標準化的過程當中,一些動態化業務實踐也沉澱到了容器之中,例如:

  • 動態腳本:script支持加載網絡資源

  • 動態樣式:style支持加載網絡資源

  • 動態路由:瀏覽器支持直接經過 URL 載入、或經過iframe嵌入網絡應用程序

雖然從熱修復開始就可以從CDN拉取 JS 文件,運行時動態解釋執行了,但容器標準不只對這種方式提供了便捷支持,還將動態化的基礎能力從邏輯擴大到了視圖、樣式、靜態資源等等

至此,動態化最關鍵的基礎能力已經完備了。遷至 JavaScript 的功能模塊甚至可以進一步部署到雲端,實現離線集成、在線託管兩種模式的靈活切換

一色:同步、異步模式切換自如
完備的動態化基礎能力解鎖了許多新玩法,例如:

  • 模塊化(加載器)

  • 代碼拆分

  • ***

  • Hydration

  • lazy 組件

  • Suspense

將業務模塊(bundle)進一步拆分紅功能模塊(chunk),並將非核心模塊異步出去,實現動態按需加載,例如第三方 JS SDK、jQuery 插件、以及分享/評論/城市選擇等重磅組件

對於內容呈現的偏靜態場景,還能夠經過 *** 在服務端完成(大部分)頁面渲染工做,加快首屏內容展示

另外一方面,Hydration、lazy 組件、Suspense 等運行時特性使得在線的動態部分可以與離線的非動態部分充分融合,實現更細粒度的業務動態化,讓在線託管真正成爲一種部署選項

與此同時,動態業務自身的組件化程度也在不斷加深,前端開發的核心工做從頁面、模塊開發轉向了組件、編排邏輯開發

流雲:數據驅動的前端應用程序
組件體系趨向成熟以後,一個由來已久的概念終於完全浮出水面——數據驅動

從先後端分層的數據協議,逐漸演變成數據驅動,這裏的數據包括 3 部分:

  • 後端業務域數據

  • 前端狀態數據

  • (基於後端業務域數據的)前端衍生數據

將這些數據填入業務組件,便可渲染出完整的功能模塊(不管是在客戶端仍是服務端),再將其放置到視圖容器中合適的坑位裏,就完成了一次組件級的「發佈」過程

這種模式涉及 5 個重要環節:

  • 業務數據(包括後端業務域數據和前端衍生數據)的生產

  • 業務組件(包括前端狀態數據)的生產和維護

  • 組件的渲染(業務數據 + 業務組件 = 功能模塊)

  • 坑位的生產

  • 功能模塊的投放

其中,業務組件、坑位是進一步動態化的關鍵,可分爲 4 個階段:

  • 一個蘿蔔一個坑:靜態業務組件 + 靜態坑位

    • 一個蘿蔔處處扔:靜態業務組件 + 動態坑位
  • 多個蘿蔔輪番扔:動態業務組件 + 靜態坑位

  • 多個蘿蔔處處扔:動態業務組件 + 動態坑位

要達到多個蘿蔔處處扔的組件級動態化終極目標,就要求可以動態發佈業務組件、動態發佈坑位

交融:動態業務組件 + 動態坑位
從端和雲的視角來看,業務組件也能夠看做數據(雲)的一部分,相比之下坑位與端的關聯更爲緊密,而動態化的惟一手段就是將端側的東西搬到雲上去,因此要解決的關鍵問題是如何實現坑位的動態化

有 2 個思路:

  • 幹掉坑位的概念:將坑位的概念從組件級擴展到頁面級,一個頁面容器(一個 URL)即一個坑位

  • 將坑位組件化:提供標準的坑位組件,就像iframe

頁面是一種自然的動態坑位,可打開一個新的頁面容器加載任意 URL

對於除頁面以外的其它佈局容器,如對話框、消息條、Banner 位、腰封等等,能夠將坑位標準化成容器組件,與業務組件一併動態發佈,將坑位的租賃關係維護在服務端,做爲數據驅動的數據之一

至此,先後端分層的界限幾經從新定義,終於迎來了 JSP/PHP 融合數據與模板的黃金年代……

相關文章
相關標籤/搜索