新聞中心
想做好前端很難,做出可擴(kuò)展的前端,從而讓多個(gè)團(tuán)隊(duì)可以同時(shí)投身于一項(xiàng)復(fù)雜的大型產(chǎn)品項(xiàng)目就更難了。本文將介紹前端領(lǐng)域最近的一項(xiàng)變革:單體前端架構(gòu)正在過渡到許多較小、較易管理的前端架構(gòu)。我們還會展示這種新的體系結(jié)構(gòu)怎樣提升前端團(tuán)隊(duì)的效率和表現(xiàn)。除了討論這種新趨勢的好處與代價(jià)外,我們還將介紹一些可行的實(shí)現(xiàn)方案,并深入分析一個(gè)完整的微前端應(yīng)用案例。

創(chuàng)新互聯(lián)建站服務(wù)緊隨時(shí)代發(fā)展步伐,進(jìn)行技術(shù)革新和技術(shù)進(jìn)步,經(jīng)過十多年的發(fā)展和積累,已經(jīng)匯集了一批資深網(wǎng)站策劃師、設(shè)計(jì)師、專業(yè)的網(wǎng)站實(shí)施團(tuán)隊(duì)以及高素質(zhì)售后服務(wù)人員,并且完全形成了一套成熟的業(yè)務(wù)流程,能夠完全依照客戶要求對網(wǎng)站進(jìn)行成都網(wǎng)站制作、成都做網(wǎng)站、外貿(mào)營銷網(wǎng)站建設(shè)、建設(shè)、維護(hù)、更新和改版,實(shí)現(xiàn)客戶網(wǎng)站對外宣傳展示的首要目的,并為客戶企業(yè)品牌互聯(lián)網(wǎng)化提供全面的解決方案。
微服務(wù)近年來大受歡迎,許多組織轉(zhuǎn)向了微服務(wù)以克服大型單體后端架構(gòu)的局限。但雖然微服務(wù)在服務(wù)端很流行,很多企業(yè)在前端代碼庫上仍然在沿用問題多多的單體架構(gòu)。
也許你想構(gòu)建一個(gè)漸進(jìn)式或響應(yīng)式的 Web 應(yīng)用,但卻找不到一種將這些功能集成進(jìn)現(xiàn)有代碼中的簡單途徑;也許你想嘗試 JavaScript 語言的新功能(或者是其他可以編譯為 JS 的某種語言),但你卻無法將關(guān)鍵的構(gòu)建工具融入已有的構(gòu)建流程;或者你只是想擴(kuò)展開發(fā)流程,讓多個(gè)團(tuán)隊(duì)可以同時(shí)開發(fā)一種產(chǎn)品,但現(xiàn)有單體架構(gòu)中的耦合度與復(fù)雜性讓團(tuán)隊(duì)間的合作變得磕磕絆絆。這些都是很現(xiàn)實(shí)的問題,都會影響你們向客戶交付高質(zhì)量體驗(yàn)的能力。
微前端的定義
最近業(yè)界越來越關(guān)注復(fù)雜的現(xiàn)代化 Web 開發(fā)需要怎樣的整體架構(gòu)和組織結(jié)構(gòu)這個(gè)問題。于是我們開始看到單體前端正在分解為更小、更簡單的模塊,這些模塊可以各自獨(dú)立開發(fā)、測試和部署,而它們組合在一起仍然對客戶表現(xiàn)為一件單一完整的產(chǎn)品。我們將這種技術(shù)稱為 微前端,其定義為:
“微前端是一種架構(gòu)風(fēng)格,其中眾多獨(dú)立交付的前端應(yīng)用組合成一個(gè)大型整體?!?/p>
我們認(rèn)為微前端的主要好處有:
- 更小,更緊密且更易維護(hù)的代碼庫。
- 組織更具擴(kuò)展能力,其團(tuán)隊(duì)更加獨(dú)立自治。
- 能夠以更加增量式的風(fēng)格來升級、更新前端,甚至重寫部分前端代碼。
這些核心優(yōu)勢與微服務(wù)的優(yōu)勢基本一致,這也不是什么巧合。
當(dāng)然,軟件架構(gòu)領(lǐng)域沒有免費(fèi)的午餐:一切都要付出代價(jià)。一些微前端實(shí)現(xiàn)可能導(dǎo)致重復(fù)依賴,使用戶不得不下載更多內(nèi)容。此外,大幅提升的團(tuán)隊(duì)自治水平可能會讓各個(gè)團(tuán)隊(duì)的工作愈加分裂。只不過我們認(rèn)為這些風(fēng)險(xiǎn)都能控制在合理水平上,微前端終究還是利大于弊的。
好處
我們不會從具體的技術(shù)方法或?qū)嵤┘?xì)節(jié)角度來定義微前端,而是重點(diǎn)關(guān)注它的屬性和好處。
增量升級
對于許多組織來說,追求增量升級就是他們邁向微前端的***步。對他們來說,老式的大型單體前端要么是用老舊的技術(shù)棧打造的,要么就充斥著匆忙寫成的代碼,已經(jīng)到了該重寫整個(gè)前端的時(shí)候了。一次性重寫整個(gè)系統(tǒng)風(fēng)險(xiǎn)很大,我們更傾向一點(diǎn)一點(diǎn)換掉老的應(yīng)用,同時(shí)在不受單體架構(gòu)拖累的前提下為客戶不斷提供新功能。
為了做到這一點(diǎn),解決方案往往就是微前端架構(gòu)了。一旦某個(gè)團(tuán)隊(duì)掌握了在幾乎不影響舊世界的同時(shí)為生產(chǎn)環(huán)境引入新功能的訣竅,其他團(tuán)隊(duì)就會紛紛效仿。現(xiàn)有代碼仍然需要繼續(xù)維護(hù)下去,但在某些情況下還要繼續(xù)添加新功能,現(xiàn)在總算有了解決方案。
到***,我們就能更隨心所欲地改動產(chǎn)品的各個(gè)部分,并逐漸升級我們的架構(gòu)、依賴關(guān)系和用戶體驗(yàn)。當(dāng)主框架發(fā)生重大變化時(shí)每個(gè)微前端模塊都可以按需升級,不需要整體下線或一次性升級所有內(nèi)容。如果我們想要嘗試新的技術(shù)或互動模式,也能在隔離度更好的環(huán)境下做試驗(yàn)。
簡潔、解耦的代碼庫
微前端體系下,每個(gè)小模塊的代碼庫要比一個(gè)單體前端的代碼庫小很多。對開發(fā)者來說這些較小的代碼庫處理起來更簡單方便。而且微前端還能避免無關(guān)組件之間不必要的耦合,讓代碼更簡潔。我們可以在應(yīng)用的限界上下文(詳見下方鏈接)處劃出更明顯的界限,更好地避免無意間造成的這類耦合問題。
當(dāng)然,只靠架構(gòu)更迭本身(比如說“我們改成微前端吧”)并不能自動為以往的優(yōu)質(zhì)代碼生成替代品。我們要做的是設(shè)法讓糟糕的決策難以露頭,而讓正確的決策暢通無阻,從而進(jìn)入邁向成功的良性循環(huán)。例如,現(xiàn)在很難跨越限界上下文共享域模型,所以開發(fā)者就不太可能這樣做了。類似地,微前端會讓開發(fā)者更審慎地把握數(shù)據(jù)和事件在應(yīng)用的各個(gè)部分之間流動的方式,其實(shí)就算沒有微前端我們本來也應(yīng)該這樣做的!
獨(dú)立部署
就像微服務(wù)一樣,微前端的一大優(yōu)勢就是可獨(dú)立部署的能力。這種能力會縮減每次部署涉及的范圍,從而降低了風(fēng)險(xiǎn)。不管你的前端代碼是在哪里托管,怎樣托管,各個(gè)微前端都應(yīng)該有自己的持續(xù)交付管道;這些管道可以將微前端構(gòu)建、測試并部署到生產(chǎn)環(huán)境中。我們在部署各個(gè)微前端時(shí)幾乎不用考慮其他代碼庫或管道的狀態(tài);就算舊的單體架構(gòu)采用了固定、手動的按季發(fā)布周期,或者隔壁的團(tuán)隊(duì)在他們的主分支里塞進(jìn)了一個(gè)半成品或失敗的功能,也不影響我們的工作。如果某個(gè)微前端已準(zhǔn)備好投入生產(chǎn),那么它就能順利變?yōu)楫a(chǎn)品,且這一過程完全由開發(fā)和維護(hù)它的團(tuán)隊(duì)主導(dǎo)。
自治團(tuán)隊(duì)
解藕代碼庫、分離發(fā)布周期還能帶來一個(gè)高層次的好處,那就是大幅提升團(tuán)隊(duì)的獨(dú)立性;一支獨(dú)立的團(tuán)隊(duì)可以自主完成從產(chǎn)品構(gòu)思到最終發(fā)布的完整流程,有足夠的能力獨(dú)立向客戶交付價(jià)值,從而可以更快、更高效地工作。為了實(shí)現(xiàn)這一目標(biāo)需要圍繞垂直業(yè)務(wù)功能,而非技術(shù)功能來打造團(tuán)隊(duì)。一種簡單的方法是根據(jù)最終用戶將看到的內(nèi)容來劃分產(chǎn)品模塊,讓每個(gè)微前端都封裝應(yīng)用的某個(gè)頁面,并分配給一個(gè)團(tuán)隊(duì)完整負(fù)責(zé)。相比圍繞技術(shù)或“橫向”問題(如樣式、表單或驗(yàn)證)打造的團(tuán)隊(duì)相比,這種團(tuán)隊(duì)能有更高的凝聚力。
小結(jié)
簡而言之,微前端是將龐大復(fù)雜的整體分割為更小、更易于管理的模塊,然后明確它們之間的依賴關(guān)系。我們的技術(shù)決策、代碼庫、團(tuán)隊(duì)和發(fā)布流程都應(yīng)該彼此獨(dú)立,無需過多協(xié)調(diào)工作就能自主運(yùn)行并發(fā)展。
案例
假設(shè)要做一個(gè)食品外賣的網(wǎng)站。乍一看這種網(wǎng)站好像很好做,但想要做好需要在諸多細(xì)節(jié)上下足功夫:
- 應(yīng)該有一個(gè)引導(dǎo)頁面,讓顧客瀏覽并搜索餐館。顧客應(yīng)該能按照一系列參數(shù)(包括價(jià)格、菜品或訂購歷史等)來搜索并過濾餐館。
- 每家餐館都要有自己的頁面,頁面中要展示菜單,允許客戶自主選餐,還要有折扣、套餐和特殊要求選項(xiàng)。
- 顧客應(yīng)該有自己的主頁,可以用來查看訂單歷史、跟蹤外賣進(jìn)度并自定義付款選項(xiàng)
每個(gè)頁面都非常復(fù)雜,都應(yīng)該分配一個(gè)專門團(tuán)隊(duì)來負(fù)責(zé),并且每個(gè)團(tuán)隊(duì)都應(yīng)該有足夠的獨(dú)立性。各個(gè)團(tuán)隊(duì)都應(yīng)該能獨(dú)立開發(fā)、測試、部署和維護(hù)自己的代碼,而不會與其他團(tuán)隊(duì)發(fā)生沖突或需要其他團(tuán)隊(duì)配合。但在客戶這里,整個(gè)網(wǎng)站仍然應(yīng)該是一個(gè)無縫的整體。
下面我們就會圍繞這個(gè)案例來展示代碼與場景示例。
集成方法
前文對微前端的定義相當(dāng)松散,所以有很多方法都可以劃入這個(gè)范疇。本節(jié)將展示一些示例并討論它們的優(yōu)劣。這些方法在架構(gòu)上有共通之處——通常應(yīng)用中的每個(gè)頁面都有一個(gè)微前端,還有一個(gè) 容器應(yīng)用,它有以下功能:
- 呈現(xiàn)常見的頁面元素,如頁眉和頁腳。
- 解決了身份認(rèn)證和跳轉(zhuǎn)等跨領(lǐng)域問題。
- 在頁面上集成多個(gè)微前端,并告訴各個(gè)微前端該何時(shí)何地呈現(xiàn)自己。
服務(wù)器端模板組合
先來介紹一種非常新穎的前端開發(fā)方法——就是在服務(wù)器上使用多個(gè)模板或片段呈現(xiàn) HTML。首先我們要有一個(gè) index.html,其中包含所有常見的頁面元素;然后使用服務(wù)器端包含從 HTML 片段文件中插入的特定頁面內(nèi)容:
Feed me Feed me
我們使用 Nginx 提供此文件,通過匹配正在請求的 URL 來配置 $PAGE 變量:
- server {
- listen 8080;
- server_name localhost;
- root /usr/share/nginx/html;
- index index.html;
- ssi on;
- # Redirect / to /browse
- rewrite ^/$ http://localhost:8080/browse redirect;
- # Decide which HTML fragment to insert based on the URL
- location /browse {
- set $PAGE 'browse';
- }
- location /order {
- set $PAGE 'order';
- }
- location /profile {
- set $PAGE 'profile'
- }
- # All locations should render through index.html
- error_page 404 /index.html;
- }
這是相當(dāng)標(biāo)準(zhǔn)的服務(wù)器端組合方法。它之所以可以算作微前端,是因?yàn)槲覀兛梢杂纱藖矸指畲a,讓每部分代碼代表一個(gè)自包含的域概念,并由一個(gè)獨(dú)立的團(tuán)隊(duì)負(fù)責(zé)。這里沒有展示各個(gè) HTML 片段文件最終如何在 Web 服務(wù)器上呈現(xiàn),實(shí)際上它們都有自己的部署管道,改動某個(gè)頁面并不會影響其他內(nèi)容。
想要更高獨(dú)立性的話,可以為每個(gè)微前端單獨(dú)安排一個(gè)服務(wù)器負(fù)責(zé)呈現(xiàn)和服務(wù),再安排一個(gè)服務(wù)器專門向其他服務(wù)器發(fā)出請求。如果能緩存好各個(gè)響應(yīng)就不會增大延遲。
這個(gè)例子說明微前端不一定是一種新技術(shù),也不一定很復(fù)雜。只要我們的設(shè)計(jì)決策能為代碼庫和團(tuán)隊(duì)賦予更多自主權(quán),那么不管怎樣的技術(shù)棧都能為我們帶來類似的收益。
構(gòu)建時(shí)集成
還有一種方法是將每個(gè)微前端作為一個(gè)包來發(fā)布,并讓容器應(yīng)用將它們?nèi)孔鳛閹煲蕾嚢M(jìn)去。下面展示了容器的 package.json 查找本文示例應(yīng)用的方法:
- {
- "name": "@feed-me/container",
- "version": "1.0.0",
- "description": "A food delivery web app",
- "dependencies": {
- "@feed-me/browse-restaurants": "^1.2.3",
- "@feed-me/order-food": "^4.5.6",
- "@feed-me/user-profile": "^7.8.9"
- }
- }
這種辦法初看上去挺不錯(cuò)。它通常會生成一個(gè)可部署的 Javascript 包,允許我們從各種應(yīng)用中刪除常見的重復(fù)依賴。但這意味著我們修改產(chǎn)品的任何部分時(shí)都必須重新編譯和發(fā)布所有微前端。這種 齊步走的發(fā)布流程 在微服務(wù)里已經(jīng)夠讓我們好受了,所以我們強(qiáng)烈建議不要用它來實(shí)現(xiàn)微前端架構(gòu)。我們好不容易在開發(fā)和測試階段實(shí)現(xiàn)了解耦和獨(dú)立,可別再在發(fā)布階段又繞回去了。我們得在運(yùn)行時(shí)中也集成微前端。
通過 iframe 在運(yùn)行時(shí)集成
想要在瀏覽器中組合應(yīng)用,一種最簡單的方法就是用 iframe。iframe 可以輕松地用一系列獨(dú)立的子頁面構(gòu)建整個(gè)頁面。它們的樣式和全局變量也能充分隔離,不會互相干擾。
Feed me! Welcome to Feed me!
就像前文提到的服務(wù)器端包含方法一樣,用 iframe 構(gòu)建頁面并不是一種激動人心的新技術(shù)。但只要我們能精心分割好應(yīng)用并組建好團(tuán)隊(duì),那么用 iframe 就能實(shí)現(xiàn)前面提到的一系列好處。
很多人不喜歡 iframe,它也的確有一些缺陷。上面提到的簡單隔離方式確實(shí)降低了它的靈活性。用 iframe 在應(yīng)用的各個(gè)部分之間構(gòu)建集成可能會很困難,從而讓路由、歷史記錄和深層鏈接變得更加復(fù)雜;它還會影響頁面的響應(yīng)速度。
通過 JavaScript 在運(yùn)行時(shí)集成
這個(gè)方法非常靈活,應(yīng)用廣泛。每個(gè)微前端都使用


咨詢
建站咨詢