常見微前端方案

轉(zhuǎn)載請(qǐng)注明出處,點(diǎn)擊此處 查看更多精彩內(nèi)容瘾境。

iframe

iframe 是 HTML 的內(nèi)聯(lián)框架元素喳篇,表示嵌套的 Browsing Context迅矛,它能夠?qū)⒘硪粋€(gè) HTML 頁(yè)面嵌入到當(dāng)前頁(yè)面中型宝,每個(gè)嵌入的 Browsing Context 都有自己的會(huì)話歷史記錄和 DOM 樹械筛。

每個(gè)瀏覽上下文都擁有完整的文檔環(huán)境捎泻,因此頁(yè)面上每個(gè) iframe 都需要增加內(nèi)存和其它計(jì)算資源,雖然理論上來(lái)說能夠在代碼中寫出來(lái)無(wú)限多的 iframe埋哟,但是這么做可能會(huì)導(dǎo)致某些性能問題笆豁。

優(yōu)點(diǎn)

  • Web 應(yīng)用隔離的非常完美,無(wú)論是 JavaScript赤赊、CSS闯狱、DOM 都完全隔離開來(lái)。
  • 非常簡(jiǎn)單抛计,使用沒有任何心智負(fù)擔(dān)哄孤。

缺點(diǎn)

  • DOM 結(jié)構(gòu)不共享,彈窗只能在 iframe 內(nèi)部展示吹截,無(wú)法覆蓋全局瘦陈。
  • 路由狀態(tài)丟失凝危,刷新頁(yè)面會(huì)導(dǎo)致 iframe 的 url 狀態(tài)丟失、后退前進(jìn)按鈕無(wú)法使用晨逝。
  • 性能差蛾默,每次子應(yīng)用進(jìn)入都是一次瀏覽器上下文重建、資源重新加載的過程捉貌。
  • 應(yīng)用之間通信困難支鸡,全局上下文完全隔離,內(nèi)存變量不共享趁窃,無(wú)法訪問非同源的 window 對(duì)象的幾乎所有屬性牧挣,跨域通信僅可通過 window.postMessage() 來(lái)實(shí)現(xiàn)。

路由轉(zhuǎn)發(fā)

路由分發(fā)式微前端醒陆,即通過路由將不同的業(yè)務(wù)分發(fā)到不同的獨(dú)立前端應(yīng)用上瀑构。最常用的方案是通過 HTTP 服務(wù)的反向代理(如 Nginx)將不同頁(yè)面的請(qǐng)求分發(fā)到不同的服務(wù)上。

優(yōu)點(diǎn)

  • 實(shí)現(xiàn)簡(jiǎn)單刨摩。
  • 維護(hù)检碗、開發(fā)成本低。
  • 不需要對(duì)現(xiàn)有應(yīng)用進(jìn)行改造码邻。

缺點(diǎn)

  • 用戶體驗(yàn)不好折剃,每次切換應(yīng)用時(shí),瀏覽器都需要重新加載頁(yè)面像屋。
  • 子應(yīng)用之間的通信比較困難怕犁。
  • 多個(gè)子應(yīng)用無(wú)法并存。
  • 子應(yīng)用切換時(shí)需要重新登錄己莺。

動(dòng)態(tài)加載模塊

創(chuàng)建一個(gè)基座應(yīng)用奏甫,允許子應(yīng)用單獨(dú)部署。為了實(shí)現(xiàn)這一點(diǎn)凌受,創(chuàng)建一個(gè) manifest 文件阵子,記錄上線的子應(yīng)用及版本信息,當(dāng)子應(yīng)用部署更新時(shí)修改 manifest 文件胜蛉,基座應(yīng)用通過 manifest 檢查更新子應(yīng)用資源挠进。

改變每個(gè)子應(yīng)用加載的 JavaScript 文件有很多的方法:

  • Web 服務(wù)器:在你的 Web 服務(wù)器為每個(gè)子應(yīng)用的正確版本創(chuàng)建一個(gè)動(dòng)態(tài)腳本。
  • 使用模塊加載 例如 SystemJS 可以在瀏覽器通過動(dòng)態(tài) urls 下載并執(zhí)行 JavaScript 代碼誊册。

npm

每個(gè)子應(yīng)用在一個(gè)單獨(dú)的代碼倉(cāng)庫(kù)中领突,每次更新時(shí)發(fā)布一個(gè)新版本到 npm,創(chuàng)建一個(gè)基座應(yīng)用案怯,通過 npm 安裝每個(gè)子應(yīng)用君旦。

優(yōu)點(diǎn)

  • npm 安裝對(duì)于開發(fā)中更熟悉,易于搭建。

缺點(diǎn)

  • 子應(yīng)用發(fā)生變更時(shí)金砍,基座應(yīng)用需要重新安裝局蚀、重新構(gòu)建和重新部署。
  • 無(wú)法動(dòng)態(tài)安裝恕稠、卸載子應(yīng)用至会。

Web Component

Web Component 是一套不同的技術(shù),允許你創(chuàng)建可重用的定制元素(它們的功能封裝在你的代碼之外)并且在你的 Web 應(yīng)用中使用它們谱俭。

Web Components 由三項(xiàng)主要技術(shù)組成,它們可以一起使用來(lái)創(chuàng)建封裝功能的定制元素宵蛀,可以在你喜歡的任何地方重用昆著,不必?fù)?dān)心代碼沖突。

  • Custom Element(自定義元素)

    一組 JavaScript API术陶,允許您定義 Custom Elements 及其行為凑懂,然后可以在您的用戶界面中按照需要使用它們。
  • Shadow DOM(影子 DOM)

    一組 JavaScript API梧宫,用于將封裝的“影子”DOM 樹附加到元素(與主文檔 DOM 分開呈現(xiàn))并控制其關(guān)聯(lián)的功能接谨。通過這種方式,您可以保持元素的功能私有塘匣,這樣它們就可以被腳本化和樣式化脓豪,而不用擔(dān)心與文檔的其他部分發(fā)生沖突。
  • HTML Template(HTML 模板)

    <template><slot> 元素使您可以編寫不在呈現(xiàn)頁(yè)面中顯示的標(biāo)記模板忌卤。然后它們可以作為自定義元素結(jié)構(gòu)的基礎(chǔ)被多次重用扫夜。

基于 Web ComponentShadow Dom 能力,我們也可以實(shí)現(xiàn)微前端驰徊,將多個(gè)子應(yīng)用聚合起來(lái)笤闯。

const shadow = document.querySelector('#hostElement').attachShadow({mode: 'open'});
// url 為應(yīng)用的地址,基于 fetch棍厂,我們可以獲取到應(yīng)用的 html 模板颗味,添加到指定節(jié)點(diǎn)下
fetch(url).then(res => {
    shadow.innerHTML = res
});

優(yōu)點(diǎn)

  • 實(shí)現(xiàn)簡(jiǎn)單。
  • 完全技術(shù)棧無(wú)關(guān)牺弹。
  • 不需要對(duì)現(xiàn)有應(yīng)用進(jìn)行改造浦马。
  • CSS 和 JavaScript 天然隔離,互不干擾张漂。

缺點(diǎn)

  • 沒有統(tǒng)一的 Web Component 規(guī)范捐韩。
  • 瀏覽器實(shí)現(xiàn)不一致。
  • Web 組件存在向后不兼容的版本問題鹃锈。
  • 開發(fā)成本較高荤胁。

EMP

EMP 基于 Webpack5 的 Module Federation 實(shí)現(xiàn),用一個(gè)詞概括屎债,就是“去中心化”仅政,在 EMP 的方案中不需要中心化的基座垢油,每一個(gè)微前端應(yīng)用都可以通過遠(yuǎn)程調(diào)用的方式引入共享模塊。

優(yōu)點(diǎn)

  • Webpack5 Module Federation 可以保證所有子應(yīng)用依賴解耦圆丹。
  • 模塊遠(yuǎn)程 TypeScript 支持滩愁。
  • 應(yīng)用間去中心化的調(diào)用、共享模塊辫封。

缺點(diǎn)

  • 對(duì) Webpack 強(qiáng)依賴硝枉,老舊項(xiàng)目不友好。
  • 沒有有效的 CSS 沙箱和 JavaScript 沙箱倦微,需要靠用戶自覺妻味。
  • 主、子應(yīng)用的路由可能發(fā)生沖突欣福。
  • 子應(yīng)用痹鹎颍活、多應(yīng)用激活無(wú)法實(shí)現(xiàn)拓劝。

single-spa / qiankun

single-spa 是一個(gè)目前主流的微前端技術(shù)方案雏逾。

single-spa 從現(xiàn)代框架組件生命周期中獲得靈感,將生命周期應(yīng)用于整個(gè)應(yīng)用程序郑临,其主要實(shí)現(xiàn)思路:

  • 預(yù)先注冊(cè)子應(yīng)用(激活路由栖博、子應(yīng)用資源、生命周期函數(shù))厢洞。
  • 監(jiān)聽路由的變化笛匙,匹配到了激活的路由則加載子應(yīng)用資源,順序調(diào)用生命周期函數(shù)并最終渲染到容器犀变。

single-spa 未解決子應(yīng)用加載妹孙、應(yīng)用隔離、子應(yīng)用通信等問題获枝。

qiankun 微前端架構(gòu)則進(jìn)一步對(duì) single-spa 方案進(jìn)行完善蠢正,主要的完善點(diǎn):

  • 子應(yīng)用資源由 JavaScript 列表修改進(jìn)為一個(gè) url,大大減輕注冊(cè)子應(yīng)用的復(fù)雜度省店。
  • 增加資源預(yù)加載能力嚣崭,預(yù)先緩存子應(yīng)用的 HTML、JavaScript懦傍、CSS 資源雹舀,加快子應(yīng)用的打開速度。
  • 實(shí)現(xiàn)應(yīng)用隔離粗俱,完成 JavaScript 隔離方案 (window 工廠) 和 CSS 隔離方案 (類 Vue 的 scoped)说榆。
  • 提供了 @umijs/plugin-qiankunumi 應(yīng)用一鍵切換成微前端架構(gòu)系統(tǒng)。

優(yōu)點(diǎn)

  • 監(jiān)聽路由自動(dòng)的加載、卸載當(dāng)前路由對(duì)應(yīng)的子應(yīng)用签财。
  • 路由保持串慰,瀏覽器刷新、前進(jìn)唱蒸、后退邦鲫,都可以作用到子應(yīng)用。
  • 應(yīng)用間通信簡(jiǎn)單神汹,全局注入庆捺。
  • 完備的沙箱方案,JavaScript 沙箱做了 SnapshotSandbox屁魏、LegacySandbox滔以、ProxySandbox 三套漸進(jìn)增強(qiáng)方案,CSS 沙箱做了兩套 strictStyleIsolation蚁堤、experimentalStyleIsolation 兩套適用不同場(chǎng)景的方案。

缺點(diǎn)

  • 改造成本較大但狭,從 Webpack披诗、代碼、路由等等都要做一系列的適配立磁。
  • 基于路由匹配呈队,無(wú)法同時(shí)激活多個(gè)子應(yīng)用,也不支持子應(yīng)用背纾活宪摧。
  • CSS 沙箱無(wú)法絕對(duì)的隔離,JavaScript 沙箱在某些場(chǎng)景下執(zhí)行性能下降嚴(yán)重颅崩。
  • 無(wú)法支持 Vite 等 ESM 腳本運(yùn)行几于。

無(wú)界(wujie)

無(wú)界利用 iframe 的沙箱機(jī)制,將子應(yīng)用的 JavaScript 注入到基座應(yīng)用同域的 iframe 中運(yùn)行沿后,并采用 Web Component 實(shí)現(xiàn)頁(yè)面的樣式隔離沿彭。

  • 應(yīng)用加載機(jī)制和 JavaScript 沙箱機(jī)制

    將子應(yīng)用的 JavaScript 注入主應(yīng)用同域的 iframe 中運(yùn)行,iframe 是一個(gè)原生的 window 沙箱尖滚,內(nèi)部有完整的 historylocation 接口喉刘,子應(yīng)用實(shí)例運(yùn)行在 iframe 中,路由主應(yīng)用解耦漆弄,可以直接在業(yè)務(wù)組件里面啟動(dòng)應(yīng)用睦裳。
  • 路由同步機(jī)制

    劫持 iframehistory.pushStatehistory.replaceState,就可以將子應(yīng)用的 url 同步到主應(yīng)用的 query 參數(shù)上撼唾,當(dāng)刷新瀏覽器初始化 iframe 時(shí)廉邑,讀回子應(yīng)用的 url 并使用 iframehistory.replaceState 進(jìn)行同步。
  • iframe 連接機(jī)制和 CSS 沙箱機(jī)制

    無(wú)界采用 Web Component 來(lái)實(shí)現(xiàn)頁(yè)面的樣式隔離,無(wú)界會(huì)創(chuàng)建一個(gè) wujie 自定義元素鬓催,然后將子應(yīng)用的完整結(jié)構(gòu)渲染在內(nèi)部肺素。子應(yīng)用的實(shí)例在 iframe 內(nèi)運(yùn)行,DOM 在主應(yīng)用容器下的 Web Component 內(nèi)宇驾,通過代理 iframedocumentWeb Component倍靡,可以實(shí)現(xiàn)兩者的互聯(lián)。
  • 通信機(jī)制

    承載子應(yīng)用的 iframe 和主應(yīng)用是同域的课舍,所以主塌西、子應(yīng)用天然就可以很好的進(jìn)行通信,無(wú)界提供三種通信方式筝尾。
    • props 注入機(jī)制捡需,子應(yīng)用通過 $wujie.props 可以輕松拿到主應(yīng)用注入的數(shù)據(jù)。
    • 子應(yīng)用 iframe 沙箱和主應(yīng)用同源筹淫,子應(yīng)用可以直接通過 window.parent 和主應(yīng)用通信站辉。
    • 無(wú)界提供了 EventBus 實(shí)例,注入到主應(yīng)用和子應(yīng)用损姜,所有的應(yīng)用可以去中心化的進(jìn)行通信饰剥。

優(yōu)點(diǎn)

  • 多應(yīng)用同時(shí)激活在線

    框架具備同時(shí)激活多應(yīng)用,并保持這些應(yīng)用路由同步的能力摧阅。
  • 組件式的使用方式

    無(wú)需注冊(cè)汰蓉,更無(wú)需路由適配,在組件內(nèi)使用棒卷,跟隨組件裝載顾孽、卸載。
  • 應(yīng)用級(jí)別的 keep-alive

    子應(yīng)用開啟北裙妫活模式后若厚,應(yīng)用發(fā)生切換時(shí)整個(gè)子應(yīng)用的狀態(tài)可以保存下來(lái)不丟失,結(jié)合預(yù)執(zhí)行模式可以獲得類似 SSR 的打開體驗(yàn)蜒什。
  • 純凈無(wú)污染
    • 無(wú)界利用 iframeWeb Component 來(lái)搭建天然的 JavaScript 隔離沙箱和 CSS 隔離沙箱盹沈。
    • 利用 iframehistory 和主應(yīng)用的 history 在同一個(gè) top-level Browsing Context 來(lái)搭建天然的路由同步機(jī)制。
    • 副作用局限在沙箱內(nèi)部吃谣,子應(yīng)用切換無(wú)需任何清理工作乞封,沒有額外的切換成本。
  • 性能和體積兼具
    • 子應(yīng)用執(zhí)行性能和原生一致岗憋,子應(yīng)用實(shí)例運(yùn)行在 iframewindow 上下文中肃晚,避免 with(proxyWindow){code} 這樣指定代碼執(zhí)行上下文導(dǎo)致的性能下降,但是多了實(shí)例化 iframe 的一次性的開銷仔戈,可以通過 preload 提前實(shí)例化关串。
    • 體積比較輕量拧廊,借助 iframeWeb Component 來(lái)實(shí)現(xiàn)沙箱,有效的減小了代碼量晋修。
  • 開箱即用

    不管是樣式的兼容吧碾、路由的處理、彈窗的處理墓卦、熱更新的加載倦春,子應(yīng)用完成接入即可開箱即用無(wú)需額外處理,應(yīng)用接入成本也極低落剪。
  • 子應(yīng)用運(yùn)行在 iframe 中睁本,原生支持 ESM 的腳本。

缺點(diǎn)

  • iframe 的一些坑尚未解決忠怖,如路由回退問題呢堰。

micro-app

micro-app 借鑒了 Web Component 的思想,通過 Custom Element 結(jié)合自定義的 Shadow Dom凡泣,將微前端封裝成一個(gè)類 Web Component 組件枉疼,從而實(shí)現(xiàn)微前端的組件化渲染。并且由于自定義 Shadow Dom 的隔離特性鞋拟,micro-app 不需要像 single-spaqiankun 一樣要求子應(yīng)用修改渲染邏輯并暴露出方法骂维,也不需要修改 Webpack 配置,在基座應(yīng)用中嵌入一行代碼即可渲染一個(gè)微前端應(yīng)用严卖,是目前市面上接入微前端成本最低的方案席舍。

優(yōu)點(diǎn)

  • 零依賴

    micro-app 沒有任何依賴布轿,這賦予它小巧的體積和更高的擴(kuò)展性哮笆。
  • 使用簡(jiǎn)單

    我們將所有功能都封裝到一個(gè)類 Web Component 組件中,從而實(shí)現(xiàn)在基座應(yīng)用中嵌入一行代碼即可渲染一個(gè)微前端應(yīng)用汰扭。同時(shí) micro-app 還提供了 JavaScript 沙箱稠肘、樣式隔離、元素隔離萝毛、預(yù)加載项阴、數(shù)據(jù)通信、靜態(tài)資源補(bǔ)全等一系列完善的功能笆包。
  • 兼容所有框架

    為了保證各個(gè)業(yè)務(wù)之間獨(dú)立開發(fā)环揽、獨(dú)立部署的能力,micro-app 做了諸多兼容庵佣,在任何技術(shù)框架中都可以正常運(yùn)行歉胶。

缺點(diǎn)

  • 多應(yīng)用激活后無(wú)法保持子應(yīng)用的路由狀態(tài),刷新后全部丟失巴粪。
  • 對(duì)于不支持Web Component 的瀏覽器沒有做降級(jí)處理通今。
  • 支持 Vite 運(yùn)行粥谬,但必須使用 plugin 改造子應(yīng)用,且 JavaScript 代碼沒辦法做沙箱隔離辫塌。
  • 較長(zhǎng)時(shí)間未更新漏策,穩(wěn)定版最近一次發(fā)版(v0.8.10)時(shí)間是 2022.08.19,測(cè)試版最近一次發(fā)版(v1.0.0-alpha.10)時(shí)間是 2022.10.11臼氨。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末掺喻,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子一也,更是在濱河造成了極大的恐慌巢寡,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椰苟,死亡現(xiàn)場(chǎng)離奇詭異瑞躺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)靴跛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門幢泼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人洁仗,你說我怎么就攤上這事层皱。” “怎么了赠潦?”我有些...
    開封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵叫胖,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我她奥,道長(zhǎng)瓮增,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任哩俭,我火速辦了婚禮绷跑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凡资。我一直安慰自己砸捏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開白布隙赁。 她就那樣靜靜地躺著垦藏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪伞访。 梳的紋絲不亂的頭發(fā)上掂骏,一...
    開封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音咐扭,去河邊找鬼芭挽。 笑死滑废,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的袜爪。 我是一名探鬼主播蠕趁,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼辛馆!你這毒婦竟也來(lái)了俺陋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤昙篙,失蹤者是張志新(化名)和其女友劉穎腊状,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體苔可,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缴挖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了焚辅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片映屋。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖同蜻,靈堂內(nèi)的尸體忽然破棺而出棚点,到底是詐尸還是另有隱情,我是刑警寧澤湾蔓,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布瘫析,位于F島的核電站,受9級(jí)特大地震影響默责,放射性物質(zhì)發(fā)生泄漏贬循。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一傻丝、第九天 我趴在偏房一處隱蔽的房頂上張望甘有。 院中可真熱鬧诉儒,春花似錦葡缰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至温算,卻和暖如春怜校,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背注竿。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工茄茁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留魂贬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓裙顽,卻偏偏與公主長(zhǎng)得像付燥,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子愈犹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容