微前端方案

China Soft發表於2024-05-20

https://www.yinaor.com/docs/front/micro/micro-solution

微前端方案

iframe

使用 iframe 其實就可以做到多個子應用放到一個主應用的效果,但是有優點也有缺點:

✔️優點
  • 非常簡單,使用沒有任何心智負擔
  • web應用隔離的非常完美,無論是js、css、dom都完全隔離開來
❌缺點
  • 路由狀態丟失,重新整理一下,iframe的url狀態就丟失了
  • dom割裂嚴重,彈窗只能在iframe內部展示,無法覆蓋全域性
  • web應用之間通訊非常困難
  • 每次開啟白屏時間太長,對於SPA 應用來說無法接受

qiankun

single-spa是一個目前主流的微前端技術方案,其主要實現思路:

  • 預先註冊子應用(啟用路由、子應用資源、生命週期函式)
  • 監聽路由的變化,匹配到了啟用的路由則載入子應用資源,順序呼叫生命週期函式(bootstrap、mount、unmount,分別對應初始化、渲染和解除安裝)並最終渲染到容器

乾坤微前端架構則進一步對 single-spa 方案進行完善,主要的完善點:

  • 子應用資源由 js 列表修改進為一個 url,大大減輕註冊子應用的複雜度
  • 實現應用隔離,完成 js 隔離方案 (window 工廠、proxy、with(window){}) 和 css 隔離方案 (shadowDom、類 vue 的 scoped)
  • 增加資源預載入能力,預先子應用 html、js、css 資源快取下來,加快子應用的開啟速度
✔️優點
  • 監聽路由自動的載入、解除安裝當前路由對應的子應用
  • 完備的沙箱方案,js沙箱做了SnapshotSandbox、LegacySandbox、ProxySandbox三套漸進增強方案,css沙箱做了兩套strictStyleIsolation、experimentalStyleIsolation兩套適用不同場景的方案
  • 路由保持,瀏覽器重新整理、前進、後退,都可以作用到子應用
  • 應用間通訊簡單,全域性注入
❌缺點
  • 基於路由匹配,無法同時啟用多個子應用,也不支援子應用保活
  • 改造成本較大,從 webpack、程式碼、路由等等都要做一系列的適配
  • css 沙箱無法絕對的隔離,js 沙箱在某些場景下執行效能下降嚴重
  • 無法支援 vite 等 ESM 指令碼執行

micro-app

micro-app 是基於 webcomponent + qiankun sandbox 的微前端方案,號稱是目前市面上接入微前端成本最低的方案。

micro-app 並沒有沿襲 single-spa 的思路,而是借鑑了 WebComponent 的思想,透過 CustomElement 結合自定義的 ShadowDom,將微前端封裝成一個類 WebComponent 元件,從而實現微前端的元件化渲染。

並且由於自定義 ShadowDom 的隔離特性,micro-app 不需要像 single-spa 和 qiankun 一樣要求子應用修改渲染邏輯並暴露出方法,也不需要修改 webpack 配置。

微前端方案

✔️優點
  • 使用 webcomponet 載入子應用相比 single-spa 這種註冊監聽方案更加優雅
  • 複用經過大量專案驗證過 qiankun 的沙箱機制也使得框架更加可靠
  • 元件式的 api 更加符合使用習慣,支援子應用保活
  • 降低子應用改造的成本,提供靜態資源預載入能力
❌缺點
  • css 沙箱依然無法絕對的隔離
  • 支援 vite 執行,但必須使用 plugin 改造子應用,且 js 程式碼沒辦法做沙箱隔離
  • 對於不支援 webcompnent 的瀏覽器沒有做降級處理

無界

官網列出了無界方案的詳細介紹:

應用載入機制和 js 沙箱機制

將子應用的 js 注入主應用同域的 iframe 中執行,iframe 是一個原生的 window 沙箱,內部有完整的 history 和 location 介面,子應用例項 instance 執行在 iframe 中,路由也徹底和主應用解耦,可以直接在業務元件裡面啟動應用。

路由同步機制

在 iframe 內部進行 history.pushState,瀏覽器會自動的在 joint session history 中新增 iframe 的 session-history,瀏覽器的前進、後退在不做任何處理的情況就可以直接作用於子應用

劫持 iframe 的 history.pushState 和 history.replaceState,就可以將子應用的 url 同步到主應用的 query 引數上,當重新整理瀏覽器初始化 iframe 時,讀回子應用的 url 並使用 iframe 的 history.replaceState 進行同步

iframe 連線機制和 css 沙箱機制

無界採用 webcomponent 來實現頁面的樣式隔離,無界會建立一個 wujie 自定義元素,然後將子應用的完整結構渲染在內部

子應用的例項 instance 在 iframe 內執行,dom 在主應用容器下的 webcomponent 內,透過代理 iframe 的 document 到 webcomponent,可以實現兩者的互聯。

將 document 的查詢類介面:getElementsByTagName、getElementsByClassName、getElementsByName、getElementById、querySelector、querySelectorAll、head、body 全部代理到 webcomponent,這樣 instance 和 webcomponent 就精準的連結起來。

當子應用發生切換,iframe 保留下來,子應用的容器可能銷燬,但 webcomponent 依然可以選擇保留,這樣等應用切換回來將 webcomponent 再掛載回容器上,子應用可以獲得類似 vue 的 keep-alive 的能力.

通訊機制

承載子應用的 iframe 和主應用是同域的,所以主、子應用天然就可以很好的進行通訊,在無界我們提供三種通訊方式

  1. props 注入機制 子應用透過 $wujie.props 可以輕鬆拿到主應用注入的資料
  2. window.parent 通訊機制 子應用 iframe 沙箱和主應用同源,子應用可以直接透過 window.parent 和主應用通訊
  3. 去中心化的通訊機制 無界提供了 EventBus 例項,注入到主應用和子應用,所有的應用可以去中心化的進行通訊
✔️優點
  • 多應用同時啟用線上
    框架具備同時啟用多應用,並保持這些應用路由同步的能力
  • 元件式的使用方式
    無需註冊,更無需路由適配,在元件內使用,跟隨元件裝載、解除安裝
  • 應用級別的 keep-alive
    子應用開啟保活模式後,應用發生切換時整個子應用的狀態可以儲存下來不丟失,結合預執行模式可以獲得類似 ssr 的開啟體驗
  • 純淨無汙染
    • 無界利用 iframe 和 webcomponent 來搭建天然的 js 隔離沙箱和 css 隔離沙箱
    • 利用 iframe 的 history 和主應用的 history 在同一個 top-level browsing context 來搭建天然的路由同步機制
    • 副作用侷限在沙箱內部,子應用切換無需任何清理工作,沒有額外的切換成本
  • 效能和體積兼具
    • 子應用執行效能和原生一致,子應用例項 instance 執行在 iframe 的 window 上下文中,避免 with(proxyWindow){code} 這樣指定程式碼執行上下文導致的效能下降,但是多了例項化 iframe 的一次性的開銷,可以透過 preload 提前例項化
    • 體積比較輕量,藉助 iframe 和 webcomponent 來實現沙箱,有效的減小了程式碼量
  • 開箱即用
    不管是樣式的相容、路由的處理、彈窗的處理、熱更新的載入,子應用完成接入即可開箱即用無需額外處理,應用接入成本也極低

相關文章