iframe
iframe
是 html
提供的標(biāo)簽涩蜘,能加載其他web應(yīng)用的內(nèi)容,并且它能兼容所有的瀏覽器熏纯,因此同诫,你可以用它來加載任何你想要加載的web應(yīng)用。
iframe最大的特性就是提供了瀏覽器原生的硬隔離方案豆巨,不論是樣式隔離剩辟、js 隔離這類問題統(tǒng)統(tǒng)都能被完美解決。iframe與微前端概念中提到的獨立開發(fā)往扔、獨立維護(hù)、相互隔離非常的吻合熊户。
qiankun技術(shù)圓桌中一篇《關(guān)于微前端Why Not Iframe的思考》萍膛,總結(jié)的很到位,現(xiàn)復(fù)述其中的一段描述
iframe雖然基本能做到微前端所要做的所有事情嚷堡,但它的最大問題也在于他的隔離性無法被突破蝗罗,導(dǎo)致應(yīng)用間上下文無法被共享,隨之帶來開發(fā)體驗蝌戒、產(chǎn)品體驗的問題串塑。
文中對 iframe 的總結(jié):
- 不是單頁應(yīng)用,不會影響外部的路由地址北苟,無法記住當(dāng)前訪問的頁面地址桩匪,會導(dǎo)致瀏覽器刷新頁面 iframe url 狀態(tài)丟失、后退前進(jìn)按鈕無法使用友鼻。
- 彈框類的功能無法應(yīng)用到整個大應(yīng)用中傻昙,只能在對應(yīng)的窗口內(nèi)展示闺骚。
- 由于可能應(yīng)用間不是在相同的域內(nèi),主應(yīng)用的 cookie 要透傳到根域名都不同的子應(yīng)用中才能實現(xiàn)免登錄效果妆档。
- 每次子應(yīng)用進(jìn)入都是一次瀏覽器上下文重建僻爽、資源重新加載的過程,占用大量資源的同時也在極大地消耗資源贾惦。
- iframe的特性導(dǎo)致搜索引擎無法獲取到其中的內(nèi)容胸梆,進(jìn)而無法實現(xiàn)應(yīng)用的 seo
Web Components
或許很多小伙伴對Web Components不是很了解,它是由google推出的瀏覽器的原生組件,MDN對Web Components的定義是這樣的:
作為開發(fā)者,我們都知道盡可能多的重用代碼是一個好主意须板。這對于自定義標(biāo)記結(jié)構(gòu)來說通常不是那么容易 — 想想復(fù)雜的HTML(以及相關(guān)的樣式和腳本)碰镜,有時您不得不寫代碼來呈現(xiàn)自定義UI控件,并且如果您不小心的話逼纸,多次使用它們會使您的頁面變得一團(tuán)糟洋措。
Web Components旨在解決這些問題 — 它由三項主要技術(shù)組成,它們可以一起使用來創(chuàng)建封裝功能的定制元素杰刽,可以在你喜歡的任何地方重用菠发,不必?fù)?dān)心代碼沖突。
它的三項主要技術(shù)是指:
- Custom elements(自定義元素):一組JavaScript API贺嫂,允許您定義custom elements及其行為滓鸠,然后可以在您的用戶界面中按照需要使用它們。
- Shadow DOM(影子DOM):一組JavaScript API第喳,用于將封裝的“影子”DOM樹附加到元素(與主文檔DOM分開呈現(xiàn))并控制其關(guān)聯(lián)的功能糜俗。通過這種方式,您可以保持元素的功能私有曲饱,這樣它們就可以被腳本化和樣式化悠抹,而不用擔(dān)心與文檔的其他部分發(fā)生沖突。
- HTML templates(HTML模板):<template> 和 <slot> 元素使您可以編寫不在呈現(xiàn)頁面中顯示的標(biāo)記模板扩淀。然后它們可以作為自定義元素結(jié)構(gòu)的基礎(chǔ)被多次重用楔敌。
通過以上描述,再結(jié)合微前端的概念驻谆,我們來看看Web Components是如何做到微前端:
- 技術(shù)棧無關(guān):Web Components是瀏覽器原生組件卵凑,那即是在任何框架中都可以使用。
- 獨立開發(fā):使用Web Components開發(fā)的應(yīng)用無需與其他應(yīng)用間產(chǎn)生任何關(guān)聯(lián)胜臊。
- 應(yīng)用間隔離:Shadow DOM的特性勺卢,各個引入的微應(yīng)用間可以達(dá)到相互隔離的效果。
綜上所述象对,Web Components是有能力以組件加載的方式將微應(yīng)用整合在一起作為微前端的一種手段黑忱,但不幸的是,Web Components是瀏覽器的新特性,所以它的兼容性不是很好杨何,如果有兼容性要求的項目還是無法使用酱塔,具體請查看can i use。
ESM
ESM是ES Module的縮寫危虱,是Ecma script 2015中提出的一種前端模塊化手段羊娃,那么,它又是如何做到微前端的呢埃跷?其實龙屉,微前端無外乎三大特性叉瘩,無技術(shù)棧限制、應(yīng)用單獨開發(fā),多應(yīng)用整合懂鸵,只要抓住了這三個特性址貌,那就不難理解ESM如何做的了:
- 無技術(shù)棧限制:ESM加載的只是js內(nèi)容跟伏,無論哪個框架耻姥,最終都要編譯成js,因此厕吉,無論哪種框架酱固,ESM都能加載。
- 應(yīng)用單獨開發(fā):ESM只是js的一種規(guī)范头朱,不會影響應(yīng)用的開發(fā)模式运悲。
- 多應(yīng)用整合:只要將微應(yīng)用以ESM的方式暴露出來,就能正常加載项钮。
- 遠(yuǎn)程加載模塊: ESM能夠直接請求cdn資源班眯,這是它與生俱來的能力。
ESM是能做到微前端的核心思想烁巫,但是它也存在著兼容性這一大弊端署隘,盡管ESM已經(jīng)很優(yōu)秀了,但是大部分老版的瀏覽器仍然無法直接使用亚隙,這也是babel等編譯工具出現(xiàn)的原因定踱,幸運(yùn)的是,他可以通過webpack恃鞋、rollup、esbuild亦歉、snowpack等編譯工具成為兼容性的代碼恤浪。
qiankun
qiankun
特點如下:
- 基于single-spa封裝,提供了更加開箱即用的 API
- 技術(shù)棧無關(guān)肴楷,任意技術(shù)棧的應(yīng)用均可 使用/接入水由,不論是 React/Vue/Angular/JQuery 還是其他等框架
- 子應(yīng)用獨立部署
- 子應(yīng)用與主應(yīng)用無縫銜接,主應(yīng)用對子應(yīng)用可控赛蔫,子應(yīng)用可獲取主應(yīng)用資源
- HTML Entry 接入方式砂客,讓你接入微應(yīng)用像使用 iframe 一樣簡單
- 樣式隔離泥张,確保微應(yīng)用之間樣式互相不干擾
- JS 沙箱,確保微應(yīng)用之間 全局變量/事件 不沖突
- 資源預(yù)加載鞠值,在瀏覽器空閑時間預(yù)加載未打開的微應(yīng)用資源媚创,加速微應(yīng)用打開速度
- umi 插件,提供了 @umijs/plugin-qiankun 供 umi 應(yīng)用一鍵切換成微前端架構(gòu)系統(tǒng)除了最后一點拓展以外彤恶,微前端想要達(dá)到的效果都已經(jīng)達(dá)到钞钙。
qiankun原理
微前端實現(xiàn)原理是 主工程在運(yùn)行時獲取應(yīng)用配置,然后注冊應(yīng)用和路由声离,先加載主應(yīng)用(菜單等)芒炼,當(dāng)url 地址變化時,通過路由管理器和應(yīng)用管理器動態(tài)加載對應(yīng)的子應(yīng)用
路由管理器是指把所有子應(yīng)用的路由統(tǒng)一放在一個總路由里管理术徊,應(yīng)用管理器是把所有子應(yīng)用打包后的實例放在一個應(yīng)用管理器里本刽,當(dāng)URL和路由管理器中的子應(yīng)用路由匹配時,通過應(yīng)用管理器加載對應(yīng)的子應(yīng)用
actions 通信原理
Actions 通信方案是通過全局狀態(tài)池和觀察者函數(shù)進(jìn)行應(yīng)用間通信赠涮,比較適合業(yè)務(wù)劃分清晰子寓,應(yīng)用間通信較少的微前端應(yīng)用場景。
qiankun 內(nèi)部提供了 initGlobalState 方法用于注冊 MicroAppStateActions 實例用于通信世囊,該實例有三個方法别瞭,分別是:
- setGlobalState:設(shè)置 globalState - 設(shè)置新的值時,內(nèi)部將執(zhí)行 淺檢查株憾,如果檢查到 globalState 發(fā)生改變則觸發(fā)通知蝙寨,通知到所有的 觀察者 函數(shù)。
- onGlobalStateChange:注冊 觀察者 函數(shù) - 響應(yīng) globalState 變化嗤瞎,在 globalState 發(fā)生改變時觸發(fā)該 觀察者 函數(shù)墙歪。
- offGlobalStateChange:取消 觀察者 函數(shù) - 該實例不再響應(yīng) globalState 變化。
Actions 通信方案也存在一些優(yōu)缺點贝奇,優(yōu)點如下:
- 使用簡單虹菲;
-官方支持性高; - 適合通信較少的業(yè)務(wù)場景掉瞳;
缺點如下:
- 子應(yīng)用獨立運(yùn)行時毕源,需要額外配置無 Actions 時的邏輯;
- 子應(yīng)用需要先了解狀態(tài)池的細(xì)節(jié)陕习,再進(jìn)行通信霎褐;
- 由于狀態(tài)池?zé)o法跟蹤,通信場景較多時该镣,容易出現(xiàn)狀態(tài)混亂冻璃、維護(hù)困難等問題;
Shared 通信原理
適合需要跟蹤通信狀態(tài),子應(yīng)用具備獨立運(yùn)行能力省艳,較為復(fù)雜的微前端應(yīng)用娘纷。
Shared 通信方案的原理就是,主應(yīng)用基于 redux 維護(hù)一個狀態(tài)池跋炕,通過 shared 實例暴露一些方法給子應(yīng)用使用赖晶。同時,子應(yīng)用需要單獨維護(hù)一份 shared 實例枣购,在獨立運(yùn)行時使用自身的 shared 實例嬉探,在嵌入主應(yīng)用時使用主應(yīng)用的 shared 實例,這樣就可以保證在使用和表現(xiàn)上的一致性棉圈。
Shared 通信方案需要自行維護(hù)狀態(tài)池涩堤,這樣會增加項目的復(fù)雜度。好處是可以使用市面上比較成熟的狀態(tài)管理工具分瘾,如 redux胎围、mobx,可以有更好的狀態(tài)管理追蹤和一些工具集德召。
Shared 通信方案要求父子應(yīng)用都各自維護(hù)一份屬于自己的 shared 實例白魂,同樣會增加項目的復(fù)雜度。好處是子應(yīng)用可以完全獨立于父應(yīng)用運(yùn)行(不依賴狀態(tài)池)上岗,子應(yīng)用也能以最小的改動被嵌入到其他 第三方應(yīng)用 中福荸。
Shared 通信方案也可以幫助主應(yīng)用更好的管控子應(yīng)用。子應(yīng)用只可以通過 shared 實例來操作狀態(tài)池肴掷,可以避免子應(yīng)用對狀態(tài)池隨意操作引發(fā)的一系列問題敬锐。主應(yīng)用的 Shared 相對于子應(yīng)用來說是一個黑箱,子應(yīng)用只需要了解 Shared 所暴露的 API 而無需關(guān)心實現(xiàn)細(xì)節(jié)呆瞻。
優(yōu)點:
- 可以自由選擇狀態(tài)管理庫台夺,更好的開發(fā)體驗。 - 比如 redux 有專門配套的開發(fā)工具可以跟蹤狀態(tài)的變化痴脾。
- 子應(yīng)用無需了解主應(yīng)用的狀態(tài)池實現(xiàn)細(xì)節(jié)颤介,只需要了解 shared 的函數(shù)抽象,實現(xiàn)一套自身的 shared 甚至空 shared 即可赞赖,可以更好的規(guī)范子應(yīng)用開發(fā)滚朵。
- 子應(yīng)用無法隨意污染主應(yīng)用的狀態(tài)池,只能通過主應(yīng)用暴露的 shared 實例的特定方法操作狀態(tài)池前域,從而避免狀態(tài)池污染產(chǎn)生的問題始绍。
- 子應(yīng)用將具備獨立運(yùn)行的能力,Shared 通信使得父子應(yīng)用有了更好的解耦性话侄。
缺點:
- 主應(yīng)用需要單獨維護(hù)一套狀態(tài)池,會增加維護(hù)成本和項目復(fù)雜度;
- 子應(yīng)用需要單獨維護(hù)一份 shared 實例年堆,會增加維護(hù)成本吞杭;
EMP
EMP是由歡聚時代業(yè)務(wù)中臺自主研發(fā)的最年輕的單頁微前端解決方案
有如下特性:
-
基于
Webpack5
的新特性Module Federation
實現(xiàn),達(dá)到第三方依賴共享变丧,減少不必要的代碼引入的目的芽狗,什么是Module Federation這里就不再贅述。 - 每個微應(yīng)用獨立部署運(yùn)行痒蓬,并通過cdn的方式引入主程序中童擎,因此只需要部署一次,便可以提供給任何基于Module Federation的應(yīng)用使用攻晒。并且此部分代碼是遠(yuǎn)程引入顾复,無需參與應(yīng)用的打包。
- 動態(tài)更新微應(yīng)用:EMP是通過cdn加載微應(yīng)用鲁捏,因此每個微應(yīng)用中的代碼有變動時芯砸,無需重新打包發(fā)布新的整合應(yīng)用便能加載到最新的微應(yīng)用。
- 去中心化给梅,每個微應(yīng)用間都可以引入其他的微應(yīng)用假丧,無中心應(yīng)用的概念。
- 跨技術(shù)棧組件式調(diào)用动羽,提供了在主應(yīng)用框架中可以調(diào)用其他框架組件的能力(目前已支持互相調(diào)用的框架及使用方式請參閱官方文檔)包帚。
- 按需加載,開發(fā)者可以選擇只加載微應(yīng)用中需要的部分运吓,而不是強(qiáng)制只能將整個應(yīng)用全部加載渴邦。
- 應(yīng)用間通信,每一個應(yīng)用都可以進(jìn)行狀態(tài)共享羽德,就像在使用npm模塊進(jìn)行開發(fā)一樣便捷几莽。
- 生成對應(yīng)技術(shù)棧模板,它能像cerate-react-app一樣宅静,也能像create-vue-app一樣章蚣,通過指令一鍵搭建好開發(fā)環(huán)境,減少開發(fā)者的負(fù)擔(dān)姨夹。
- 遠(yuǎn)程拉取ts聲明文件纤垂,emp-cli中內(nèi)置了拉取遠(yuǎn)程應(yīng)用中代碼聲明文件的能力,讓使用ts開發(fā)的開發(fā)者不再為代碼報錯而煩惱磷账。
總結(jié)
各解決方案的利弊:
-
iframe
可以直接加載其他應(yīng)用峭沦,但無法做到單頁導(dǎo)致許多功能無法正常在主應(yīng)用中展示。 -
web Components
及ESM
是瀏覽器提供給開發(fā)者的能力逃糟,能在單頁中實現(xiàn)微前端吼鱼,不過后者需要做好代碼隔離蓬豁,并且他們都是瀏覽器的新特性,都存在兼容性問題菇肃,微前端方面的探索也不成熟地粪,只能作為面向未來的微前端手段。 -
qiankun
基本上可以稱為單頁版的 iframe琐谤,具有沙箱隔離及資源預(yù)加載的特點蟆技,幾乎無可挑剔。 -
EMP
作為最年輕微前端解決方案斗忌,也是吸收了許多web優(yōu)秀特性才誕生的质礼,它在實現(xiàn)微前端的基礎(chǔ)上,擴(kuò)充了跨應(yīng)用狀態(tài)共享织阳、跨框架組件調(diào)用眶蕉、遠(yuǎn)程拉取ts聲明文件、動態(tài)更新微應(yīng)用等能力陈哑。同時妻坝,EMP
能做到第三方依賴的共享,使代碼盡可能地重復(fù)利用惊窖,減少加載的內(nèi)容刽宪。