背景
最近項(xiàng)目開發(fā)中使用了qiankun框架去做微前端,我是屬于半懂不懂的狀態(tài),大概了解過微前端是什么,可以解決什么問題,但是沒有并系統(tǒng)的認(rèn)識和從0實(shí)戰(zhàn)過。
所以希望通過幾篇文章去重新認(rèn)識微前端這一架構(gòu),主要會從幾個(gè)方面:
- 是什么,以及為什么會出現(xiàn)
- 實(shí)現(xiàn)原理,以及主流框架
- 項(xiàng)目實(shí)戰(zhàn)
發(fā)展歷程
微服務(wù)
在說微前端之前,我們需要先了解一下后端的微服務(wù),因?yàn)槲⑶岸吮旧砭褪俏∥⒎?wù)理念而產(chǎn)生的,所以我們先對微服務(wù)做一個(gè)簡單的認(rèn)識:
2014年,Martin Fowler 與 James Lewis 共同提出了微服務(wù)的概念,定義了微服務(wù)是由以單一應(yīng)用程序構(gòu)成的小服務(wù),自己擁有自己的進(jìn)程與輕量化處理,服務(wù)依業(yè)務(wù)功能設(shè)計(jì),以全自動(dòng)的方式部署,與其他服務(wù)使用HTTP API通信。同時(shí)服務(wù)會使用最小的規(guī)模的集中管理 (例如 Docker) 能力,服務(wù)可以用不同的編程語言與數(shù)據(jù)庫等組件實(shí)現(xiàn) —— 維基百科 微服務(wù)。
微服務(wù)架構(gòu),通常拿來對比的架構(gòu)是單體軟件架構(gòu),單體軟件存在以下幾個(gè)問題:
- 所有功能耦合在一起,互相影響,最終難以管理
- 哪怕只修改一行代碼,整個(gè)軟件就要重新構(gòu)建和部署,成本非常高
- 不可能每個(gè)功能單獨(dú)開發(fā)和測試,只能整體開發(fā)和測試,導(dǎo)致必須采用瀑布式開發(fā)模型
因此開始出現(xiàn)將單體軟件拆成一個(gè)個(gè)功能單元服務(wù)+通訊協(xié)議組成,這種叫面向服務(wù)(service-oriented architecture,簡稱 SOA)架構(gòu),也是微服務(wù)的雛形。
因此微服務(wù)架構(gòu)的等于面向服務(wù)架構(gòu),它有多種實(shí)現(xiàn)方案,其中最佳實(shí)踐是基于Docker容器實(shí)現(xiàn)的。
微服務(wù)的幾大特性:
- 敏捷性, 可快速迭代自己的微服務(wù)
- 彈性部署,快速持續(xù)集成與部署,服務(wù)獨(dú)立性增加了應(yīng)用程序應(yīng)對故障的彈性
- 技術(shù)自由,可以自由選擇最佳工具來解決他們的具體問題
- 可重復(fù)使用的代碼,可以將專為某項(xiàng)功能編寫的服務(wù)可以用作另一項(xiàng)功能的構(gòu)建塊
Ok,微服務(wù)了解到這里基本上就有大概的認(rèn)知,微服務(wù)當(dāng)然不只是這些,還有一些其他技術(shù)點(diǎn),如:服務(wù)發(fā)現(xiàn)、事件傳播等。
微前端
了解完微服務(wù),那么微前端概念是什么開始提出的呢?
微前端 這個(gè)名詞,第一次被提出還是在2016年底,那是在 ThoughtWorks Technology Radar。這個(gè)概念將微服務(wù)這個(gè)被廣泛應(yīng)用于服務(wù)端的技術(shù)范式擴(kuò)展到前端領(lǐng)域。
微前端是一種多個(gè)團(tuán)隊(duì)通過獨(dú)立發(fā)布功能的方式來共同構(gòu)建現(xiàn)代化 web 應(yīng)用的技術(shù)手段及方法策略。 —— 微前端的完整介紹
簡單的說,微前端架構(gòu)是從微服務(wù)理念擴(kuò)展而來的,一個(gè)適用于前端的微服務(wù)架構(gòu)。
微前端
是什么
從上面發(fā)展歷程我們對微前端架構(gòu)有個(gè)簡單認(rèn)知和它的定義,接下來我們通過不同類型的做比較去對微前端做更深的認(rèn)知。
單體巨石 VS 微前端
用單體巨石架構(gòu)和微前端架構(gòu)做一個(gè)比較,能更好的理解微前端架構(gòu),具體如下圖所示:

簡單的講,就是將原本耦合在一起的單體巨石應(yīng)用按照一定原則拆分成各種微前端小應(yīng)用,最簡單的拆分方案就是和微服務(wù)做一一映射。
組件 VS 微前端
我們再從另外一個(gè)角度的去看待微前端,假設(shè)將微前端看做組件,是不是就好理解多了,只不過這個(gè)組件有點(diǎn)大,功能比較齊全,沒有對外提供參數(shù)配置。
但是從兩者的實(shí)際應(yīng)用場景來說,還是有很多不同的地方,具體如下:
- 從應(yīng)用場景來看,組件是不可運(yùn)行,被調(diào)用的,是應(yīng)用中一部分,而微前端是完整可運(yùn)行的一個(gè)應(yīng)用
- 從技術(shù)上來看,組件是基于某個(gè)框架實(shí)現(xiàn)的,而微前端應(yīng)用不依賴任何框架,但是微前端架構(gòu)會依賴某個(gè)框架實(shí)現(xiàn)
總結(jié)
微前端架構(gòu),就是把復(fù)雜問題簡單化,每個(gè)微前端項(xiàng)目都只需要關(guān)心自己的事情。因此微前端架構(gòu)的核心思維如下:
-
技術(shù)不可知,每個(gè)微前端都應(yīng)該選擇自己的技術(shù)棧和技術(shù)進(jìn)化路線,而不是和其他團(tuán)隊(duì)保持一致,同時(shí)架構(gòu)師應(yīng)該考慮的是如何高效的提供可復(fù)用的WebComponent會成為核心問題 -
環(huán)境隔離,微前端架構(gòu)中每個(gè)子項(xiàng)目不共享運(yùn)行時(shí)環(huán)境,即是:不依賴共享狀態(tài)或全局變量,同時(shí)也可以通過命名規(guī)范(如:前綴)或命名空間,去隔離每個(gè)微前端應(yīng)用 -
原生API優(yōu)先,使用 用于通信的原生瀏覽器事件機(jī)制 ,而不是自己構(gòu)建一個(gè)PubSub系統(tǒng) -
獨(dú)立性,微前端架構(gòu)中每個(gè)子項(xiàng)目是完整的,可以獨(dú)立運(yùn)行、獨(dú)立開發(fā)、獨(dú)立部署 -
高可用,微前端架構(gòu)是高可用的,即使某個(gè)子應(yīng)用異常也不會影響其他子應(yīng)用的訪問
以上就是要實(shí)現(xiàn)微前端架構(gòu)所需要考慮的點(diǎn),同時(shí)也是架構(gòu)中的核心思維。
缺點(diǎn)
微前端架構(gòu)在上面描述了很多優(yōu)勢,但是如果沒做好架構(gòu)設(shè)計(jì),它也可能會帶來一些問題,因此我們需要提前了解微前端架構(gòu)可能會帶來的缺陷:
- 增加運(yùn)維成本,因?yàn)橛稍局恍枰l(fā)布一個(gè)應(yīng)用,變成需要發(fā)布N個(gè)應(yīng)用
- 拆分粒度越小,架構(gòu)越復(fù)雜,開發(fā)維護(hù)成本越高
- 微前端支持不同技術(shù)棧,那么也帶來了不同技術(shù)棧帶來技術(shù)棧混亂的風(fēng)險(xiǎn),同時(shí)也提高了開發(fā)維護(hù)成本
- 微前端架構(gòu)本身就是將項(xiàng)目完全獨(dú)立,可能導(dǎo)致部分公共代碼無法通用
- 還有一些其他問題,如:當(dāng)采用某類微前端框架增加開發(fā)成本等
上面這些問題,在項(xiàng)目是否要用微前端架構(gòu)都需要考慮的事情,但是也有一句話可以提供給大家參考。
工程就是權(quán)衡的藝術(shù),而微服務(wù)(microframeworks)架構(gòu)給你提供了一個(gè)可以權(quán)衡的維度。
了解完是什么,接下來就當(dāng)項(xiàng)目中要實(shí)施微前端架構(gòu)的時(shí)候要怎么做了。
怎么做
在項(xiàng)目要實(shí)施微前端架構(gòu),主要有幾個(gè)工作項(xiàng):
- 首先,就是需要搞清楚如何將項(xiàng)目拆分一個(gè)個(gè)微前端子項(xiàng)目
- 其次,選型,采用哪種微前端框架去實(shí)施
- 最后,使用漸進(jìn)式方案去實(shí)施,而不是一口氣全切換,如果是新項(xiàng)目直接采用微前端架構(gòu),那么這里推薦采用Monorepo大倉+微前端,這里會讓極大降低項(xiàng)目的管理成本。
如何拆分
微前端架構(gòu)主要工作就是拆分,那么問題來了,我們應(yīng)該依據(jù)什么樣的標(biāo)準(zhǔn)去拆分呢?我們大體可以從下幾點(diǎn)去考慮:
- 第一,拆分條件,項(xiàng)目是否適合微前端架構(gòu)
- 第二,拆分原則,項(xiàng)目拆分時(shí)候需要遵循的設(shè)計(jì)原則
- 第三,拆分方法,項(xiàng)目拆分可以依據(jù)哪些因素進(jìn)行拆分
拆分條件
我們要對項(xiàng)目進(jìn)行微前端架構(gòu)設(shè)計(jì)的時(shí)候,我們應(yīng)該從下面幾方面去考慮是否適合:
- 是否有快速迭代的需求,如果有快速迭代需求,則表示業(yè)務(wù)需要快速響應(yīng),那么采用微前端架構(gòu)去拆分,不僅支持快速迭代,還支持業(yè)務(wù)快速試錯(cuò)
- 是否有代碼提交出現(xiàn)大量沖突,如果有,則表示代碼管理成本較高,微前端架構(gòu)可以降低項(xiàng)目的管理成本
- 是否小功能需要等待大版本的場景,如果有,則表示小功能會影響到大版本的功能,這個(gè)時(shí)候微前端架構(gòu)的
獨(dú)立發(fā)布特性,可隨時(shí)回滾,風(fēng)險(xiǎn)變小,時(shí)間變短,影響面小,從而降低大版本發(fā)布延期風(fēng)險(xiǎn)
從上面幾個(gè)方面,我們可以很清晰的判斷當(dāng)前項(xiàng)目是否需要做微前端架構(gòu)調(diào)整,只有這個(gè)時(shí)候,微前端的拆分才是有確定收益的,增加的運(yùn)維成本才是值得的。
拆分原則
當(dāng)我們面對需要拆分微前端的時(shí)候,以下幾個(gè)原則可以作為參考:
- 單一職責(zé)原則,每個(gè)微前端只需關(guān)心自己的業(yè)務(wù)規(guī)則,確保職責(zé)單一,避免職責(zé)交叉
- 服務(wù)自治原則,每個(gè)微前端的開發(fā),必須擁有開發(fā)、測試、運(yùn)維、部署等整個(gè)過程,表示該應(yīng)用可以獨(dú)立運(yùn)行而不需要依賴其他應(yīng)用
- 持續(xù)演進(jìn)原則,單體架構(gòu)向微服務(wù)架構(gòu)拆分過程中,無法做到一蹴而就,應(yīng)逐步拆分細(xì)化,持續(xù)演進(jìn),避免微服務(wù)數(shù)量的瞬間爆炸性增長
- 服務(wù)粒度適中,先粗后細(xì)的原則,再按照拆分條件判斷粗粒度的微前端是否需要拆分
- 避免循環(huán)依賴,循環(huán)依賴的情況會導(dǎo)致微前端在迭代發(fā)布的時(shí)候不知道優(yōu)先發(fā)布哪個(gè),在拆分的時(shí)候需要考慮,針對依賴部分進(jìn)行下沉,拆分成公共模塊
- 橫向拆分原則,拆分微前端應(yīng)該按照依賴層次的橫向去拆,而不是縱向拆分,因?yàn)椴鸱衷缴?,維護(hù)成本越高
拆分方法
以上兩個(gè)主要針對拆分的假設(shè)條件,當(dāng)真正去拆分操作的時(shí)候,我們應(yīng)當(dāng)從這些方面去入手:
- 按照業(yè)務(wù)領(lǐng)域,參考領(lǐng)域模型,將同類業(yè)務(wù)歸為同一個(gè)微前端,按照單一職責(zé)原則、功能完整性進(jìn)行拆分
- 按照組織架構(gòu),應(yīng)盡量避免對組織架構(gòu)和團(tuán)隊(duì)的調(diào)整,避免由于功能的重新劃分,而增加大量且不必要的團(tuán)隊(duì)之間的溝通成本
- 按照技術(shù)棧,簡單點(diǎn)說React的技術(shù)棧放一個(gè)微前端,Vue的技術(shù)棧放另外一個(gè)微前端
- 按需求迭代頻率,將迭代頻率高的放在一個(gè)微前端,頻率低放在另外一個(gè)微前端
學(xué)會了拆分方法,里面的優(yōu)先級應(yīng)該有大概排序,業(yè)務(wù)領(lǐng)域 > 組織架構(gòu) > 技術(shù)棧 > 需求迭代頻率,我推薦的做法如下:
- 先按照業(yè)務(wù)領(lǐng)域去拆分
- 拆分的粒度不夠,還要再拆分就按照組織結(jié)構(gòu)再拆分
- 再往下,就是按照技術(shù)棧拆分
- 再往下,就是需求迭代頻率
微前端框架
了解完如何拆分,那么接下來就是對微前端架構(gòu)實(shí)現(xiàn)的框架進(jìn)行選型,下面是我從網(wǎng)上收集目前市場主流的幾大微前端框架:
- single-spa,將多個(gè)單頁面應(yīng)用聚合為一個(gè)整體應(yīng)用的 JavaScript 微前端框架
- qiankun,基于single-spa,能更簡單、無痛構(gòu)建可用微前端架構(gòu)的框架
- 無界,基于iframe,實(shí)現(xiàn)路由同步機(jī)制的微前端架構(gòu)框架
- micro-app,借鑒WebComponent思想,結(jié)合自定義的ShadowDom,將微前端封裝成一個(gè)類WebComponent組件的微前端框架
- webpack 模塊聯(lián)邦,在webpack構(gòu)建時(shí)候加載遠(yuǎn)程應(yīng)用而實(shí)現(xiàn)的微前端架構(gòu)方案
以上,就是目前實(shí)現(xiàn)微前端架構(gòu)的主流框架,當(dāng)然每個(gè)框架都自己的優(yōu)缺點(diǎn),我們在選型的時(shí)候主要還是通過以下幾點(diǎn)去判斷是否適合:
- 對現(xiàn)有項(xiàng)目是否需要改造,改造成本多少
- 是否有學(xué)習(xí)成本,學(xué)習(xí)成本有多復(fù)雜
- 未來是否足夠的擴(kuò)展性
- 團(tuán)隊(duì)內(nèi)是否有熟悉、精通該選型的人,否則遇到問題,容易入坑
- 項(xiàng)目維護(hù)的情況,issue 是否有響應(yīng),迭代是否在正常進(jìn)行
到了這里,本篇介紹微前端架構(gòu)基本上就結(jié)束了,雖然很多理論知識,但是我們可以再次回顧一下,總結(jié)一下要點(diǎn):
- 微前端架構(gòu)源自微服務(wù)架構(gòu),兩者主要都是為了解決巨石應(yīng)用的痛點(diǎn),迭代慢、開發(fā)復(fù)雜
- 微前端架構(gòu)拆分需要注意幾個(gè)點(diǎn):拆分條件、拆分原則和拆分方法
- 微前端架構(gòu)主流框架:single-spa、qiankun、無界、micro-app、webpack 模塊聯(lián)邦等
當(dāng)然,我不會只寫理論知識點(diǎn),后面我會針對每個(gè)框架的寫一篇深入實(shí)戰(zhàn)文章,從背后原理,適用場景去一一描述,前端架構(gòu)之路不好走,希望大家一起努力加油。
其他概念
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)
要了解一個(gè)新的東西,首先弄明白它解決了什么問題?領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)主要是為了解決:
- 幫助團(tuán)隊(duì)更好理解業(yè)務(wù)世界
- 能協(xié)助開發(fā)構(gòu)建良好的設(shè)計(jì)
- 降低業(yè)務(wù)邏輯與開發(fā)邏輯的耦合,降低復(fù)雜性
那么現(xiàn)在,我們就明白領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)是什么了?它是強(qiáng)調(diào)業(yè)務(wù)概念、專業(yè)術(shù)語的開發(fā)設(shè)計(jì)理念。以下是一些官方解釋,后面在前端架構(gòu)系列文里,會寫專門文章做深入介紹:
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(Domain-Driven Design,簡稱DDD)是一種強(qiáng)調(diào)業(yè)務(wù)概念、專業(yè)術(shù)語以及原則的開發(fā)范式,旨在幫助用戶,團(tuán)隊(duì)和軟件開發(fā)者來解決復(fù)雜的信息系統(tǒng)和軟件。它使用圖形模型作為核心,其目標(biāo)是使開發(fā)者能夠理解、分析和把握業(yè)務(wù)概念,并將這些概念轉(zhuǎn)化為可操作的軟件?!?【ChatGPT回答】
領(lǐng)域模型
領(lǐng)域模型,來自領(lǐng)域驅(qū)動(dòng)架構(gòu)(DDD)中的一個(gè)概念,與開發(fā)模型(解決實(shí)際問題所抽象出來的概念模型)設(shè)計(jì)模型(描述了所要構(gòu)建的系統(tǒng))不同的是,領(lǐng)域模型是表達(dá)與業(yè)務(wù)相關(guān)的事實(shí),它更加關(guān)注業(yè)務(wù)知識,能否顯性化、清晰的表達(dá)業(yè)務(wù)語義。
參考資料
-模塊聯(lián)邦在微前端架構(gòu)中的實(shí)踐
-微服務(wù)是什么? —— 阮一峰
-微前端的完整介紹
-領(lǐng)域驅(qū)動(dòng)架構(gòu)(DDD)建模中的模型到底是什么?
更多精彩內(nèi)容,可以到個(gè)人博客訪問:【qborfy的個(gè)人博客】。