自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

大前端時代下的微前端架構(gòu):增量升級、代碼解耦、獨立部署

開發(fā) 架構(gòu)
想做好前端很難,做出可擴(kuò)展的前端,從而讓多個團(tuán)隊可以同時投身于一項復(fù)雜的大型產(chǎn)品項目就更難了。本文將介紹前端領(lǐng)域最近的一項變革:單體前端架構(gòu)正在過渡到許多較小、較易管理的前端架構(gòu)。

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

[[268516]]

微服務(wù)近年來大受歡迎,許多組織轉(zhuǎn)向了微服務(wù)以克服大型單體后端架構(gòu)的局限。但雖然微服務(wù)在服務(wù)端很流行,很多企業(yè)在前端代碼庫上仍然在沿用問題多多的單體架構(gòu)。

也許你想構(gòu)建一個漸進(jìn)式或響應(yīng)式的 Web 應(yīng)用,但卻找不到一種將這些功能集成進(jìn)現(xiàn)有代碼中的簡單途徑;也許你想嘗試 JavaScript 語言的新功能(或者是其他可以編譯為 JS 的某種語言),但你卻無法將關(guān)鍵的構(gòu)建工具融入已有的構(gòu)建流程;或者你只是想擴(kuò)展開發(fā)流程,讓多個團(tuán)隊可以同時開發(fā)一種產(chǎn)品,但現(xiàn)有單體架構(gòu)中的耦合度與復(fù)雜性讓團(tuán)隊間的合作變得磕磕絆絆。這些都是很現(xiàn)實的問題,都會影響你們向客戶交付高質(zhì)量體驗的能力。

微前端的定義

最近業(yè)界越來越關(guān)注復(fù)雜的現(xiàn)代化 Web 開發(fā)需要怎樣的整體架構(gòu)和組織結(jié)構(gòu)這個問題。于是我們開始看到單體前端正在分解為更小、更簡單的模塊,這些模塊可以各自獨立開發(fā)、測試和部署,而它們組合在一起仍然對客戶表現(xiàn)為一件單一完整的產(chǎn)品。我們將這種技術(shù)稱為 微前端,其定義為:

“微前端是一種架構(gòu)風(fēng)格,其中眾多獨立交付的前端應(yīng)用組合成一個大型整體。” 

大前端時代下的微前端架構(gòu):增量升級、代碼解耦、獨立部署

我們認(rèn)為微前端的主要好處有:

  • 更小,更緊密且更易維護(hù)的代碼庫。
  • 組織更具擴(kuò)展能力,其團(tuán)隊更加獨立自治。
  • 能夠以更加增量式的風(fēng)格來升級、更新前端,甚至重寫部分前端代碼。

這些核心優(yōu)勢與微服務(wù)的優(yōu)勢基本一致,這也不是什么巧合。

當(dāng)然,軟件架構(gòu)領(lǐng)域沒有免費的午餐:一切都要付出代價。一些微前端實現(xiàn)可能導(dǎo)致重復(fù)依賴,使用戶不得不下載更多內(nèi)容。此外,大幅提升的團(tuán)隊自治水平可能會讓各個團(tuán)隊的工作愈加分裂。只不過我們認(rèn)為這些風(fēng)險都能控制在合理水平上,微前端終究還是利大于弊的。

好處

我們不會從具體的技術(shù)方法或?qū)嵤┘?xì)節(jié)角度來定義微前端,而是重點關(guān)注它的屬性和好處。

增量升級

對于許多組織來說,追求增量升級就是他們邁向微前端的***步。對他們來說,老式的大型單體前端要么是用老舊的技術(shù)棧打造的,要么就充斥著匆忙寫成的代碼,已經(jīng)到了該重寫整個前端的時候了。一次性重寫整個系統(tǒng)風(fēng)險很大,我們更傾向一點一點換掉老的應(yīng)用,同時在不受單體架構(gòu)拖累的前提下為客戶不斷提供新功能。

為了做到這一點,解決方案往往就是微前端架構(gòu)了。一旦某個團(tuán)隊掌握了在幾乎不影響舊世界的同時為生產(chǎn)環(huán)境引入新功能的訣竅,其他團(tuán)隊就會紛紛效仿?,F(xiàn)有代碼仍然需要繼續(xù)維護(hù)下去,但在某些情況下還要繼續(xù)添加新功能,現(xiàn)在總算有了解決方案。

到***,我們就能更隨心所欲地改動產(chǎn)品的各個部分,并逐漸升級我們的架構(gòu)、依賴關(guān)系和用戶體驗。當(dāng)主框架發(fā)生重大變化時每個微前端模塊都可以按需升級,不需要整體下線或一次性升級所有內(nèi)容。如果我們想要嘗試新的技術(shù)或互動模式,也能在隔離度更好的環(huán)境下做試驗。

簡潔、解耦的代碼庫

微前端體系下,每個小模塊的代碼庫要比一個單體前端的代碼庫小很多。對開發(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)用的各個部分之間流動的方式,其實就算沒有微前端我們本來也應(yīng)該這樣做的!

獨立部署

就像微服務(wù)一樣,微前端的一大優(yōu)勢就是可獨立部署的能力。這種能力會縮減每次部署涉及的范圍,從而降低了風(fēng)險。不管你的前端代碼是在哪里托管,怎樣托管,各個微前端都應(yīng)該有自己的持續(xù)交付管道;這些管道可以將微前端構(gòu)建、測試并部署到生產(chǎn)環(huán)境中。我們在部署各個微前端時幾乎不用考慮其他代碼庫或管道的狀態(tài);就算舊的單體架構(gòu)采用了固定、手動的按季發(fā)布周期,或者隔壁的團(tuán)隊在他們的主分支里塞進(jìn)了一個半成品或失敗的功能,也不影響我們的工作。如果某個微前端已準(zhǔn)備好投入生產(chǎn),那么它就能順利變?yōu)楫a(chǎn)品,且這一過程完全由開發(fā)和維護(hù)它的團(tuán)隊主導(dǎo)。 

大前端時代下的微前端架構(gòu):增量升級、代碼解耦、獨立部署

自治團(tuán)隊

解藕代碼庫、分離發(fā)布周期還能帶來一個高層次的好處,那就是大幅提升團(tuán)隊的獨立性;一支獨立的團(tuán)隊可以自主完成從產(chǎn)品構(gòu)思到最終發(fā)布的完整流程,有足夠的能力獨立向客戶交付價值,從而可以更快、更高效地工作。為了實現(xiàn)這一目標(biāo)需要圍繞垂直業(yè)務(wù)功能,而非技術(shù)功能來打造團(tuán)隊。一種簡單的方法是根據(jù)最終用戶將看到的內(nèi)容來劃分產(chǎn)品模塊,讓每個微前端都封裝應(yīng)用的某個頁面,并分配給一個團(tuán)隊完整負(fù)責(zé)。相比圍繞技術(shù)或“橫向”問題(如樣式、表單或驗證)打造的團(tuán)隊相比,這種團(tuán)隊能有更高的凝聚力。

大前端時代下的微前端架構(gòu):增量升級、代碼解耦、獨立部署

小結(jié)

簡而言之,微前端是將龐大復(fù)雜的整體分割為更小、更易于管理的模塊,然后明確它們之間的依賴關(guān)系。我們的技術(shù)決策、代碼庫、團(tuán)隊和發(fā)布流程都應(yīng)該彼此獨立,無需過多協(xié)調(diào)工作就能自主運行并發(fā)展。

案例

假設(shè)要做一個食品外賣的網(wǎng)站。乍一看這種網(wǎng)站好像很好做,但想要做好需要在諸多細(xì)節(jié)上下足功夫:

  • 應(yīng)該有一個引導(dǎo)頁面,讓顧客瀏覽并搜索餐館。顧客應(yīng)該能按照一系列參數(shù)(包括價格、菜品或訂購歷史等)來搜索并過濾餐館。
  • 每家餐館都要有自己的頁面,頁面中要展示菜單,允許客戶自主選餐,還要有折扣、套餐和特殊要求選項。
  • 顧客應(yīng)該有自己的主頁,可以用來查看訂單歷史、跟蹤外賣進(jìn)度并自定義付款選項

每個頁面都非常復(fù)雜,都應(yīng)該分配一個專門團(tuán)隊來負(fù)責(zé),并且每個團(tuán)隊都應(yīng)該有足夠的獨立性。各個團(tuán)隊都應(yīng)該能獨立開發(fā)、測試、部署和維護(hù)自己的代碼,而不會與其他團(tuán)隊發(fā)生沖突或需要其他團(tuán)隊配合。但在客戶這里,整個網(wǎng)站仍然應(yīng)該是一個無縫的整體。

下面我們就會圍繞這個案例來展示代碼與場景示例。

集成方法

前文對微前端的定義相當(dāng)松散,所以有很多方法都可以劃入這個范疇。本節(jié)將展示一些示例并討論它們的優(yōu)劣。這些方法在架構(gòu)上有共通之處——通常應(yīng)用中的每個頁面都有一個微前端,還有一個 容器應(yīng)用,它有以下功能:

  • 呈現(xiàn)常見的頁面元素,如頁眉和頁腳。
  • 解決了身份認(rèn)證和跳轉(zhuǎn)等跨領(lǐng)域問題。
  • 在頁面上集成多個微前端,并告訴各個微前端該何時何地呈現(xiàn)自己。 
大前端時代下的微前端架構(gòu):增量升級、代碼解耦、獨立部署

服務(wù)器端模板組合

先來介紹一種非常新穎的前端開發(fā)方法——就是在服務(wù)器上使用多個模板或片段呈現(xiàn) HTML。首先我們要有一個 index.html,其中包含所有常見的頁面元素;然后使用服務(wù)器端包含從 HTML 片段文件中插入的特定頁面內(nèi)容:

  1. <html lang="en" dir="ltr"
  2.  <head> 
  3.  <meta charset="utf-8"
  4.  <title>Feed me</title> 
  5.  </head> 
  6.  <body> 
  7.  <h1> Feed me</h1> 
  8.  <!--# include file="$PAGE.html" --> 
  9.  </body> 
  10. </html> 

我們使用 Nginx 提供此文件,通過匹配正在請求的 URL 來配置 $PAGE 變量:

  1. server { 
  2.  listen 8080; 
  3.  server_name localhost; 
  4.  root /usr/share/nginx/html; 
  5.  index index.html; 
  6.  ssi on
  7.  # Redirect / to /browse 
  8.  rewrite ^/$ http://localhost:8080/browse redirect; 
  9.  # Decide which HTML fragment to insert based on the URL 
  10.  location /browse { 
  11.  set $PAGE 'browse'
  12.  } 
  13.  location /order { 
  14.  set $PAGE 'order'
  15.  } 
  16.  location /profile { 
  17.  set $PAGE 'profile' 
  18.  } 
  19.  # All locations should render through index.html 
  20.  error_page 404 /index.html; 

這是相當(dāng)標(biāo)準(zhǔn)的服務(wù)器端組合方法。它之所以可以算作微前端,是因為我們可以由此來分割代碼,讓每部分代碼代表一個自包含的域概念,并由一個獨立的團(tuán)隊負(fù)責(zé)。這里沒有展示各個 HTML 片段文件最終如何在 Web 服務(wù)器上呈現(xiàn),實際上它們都有自己的部署管道,改動某個頁面并不會影響其他內(nèi)容。

想要更高獨立性的話,可以為每個微前端單獨安排一個服務(wù)器負(fù)責(zé)呈現(xiàn)和服務(wù),再安排一個服務(wù)器專門向其他服務(wù)器發(fā)出請求。如果能緩存好各個響應(yīng)就不會增大延遲。 

大前端時代下的微前端架構(gòu):增量升級、代碼解耦、獨立部署

這個例子說明微前端不一定是一種新技術(shù),也不一定很復(fù)雜。只要我們的設(shè)計決策能為代碼庫和團(tuán)隊賦予更多自主權(quán),那么不管怎樣的技術(shù)棧都能為我們帶來類似的收益。

構(gòu)建時集成

還有一種方法是將每個微前端作為一個包來發(fā)布,并讓容器應(yīng)用將它們?nèi)孔鳛閹煲蕾嚢M(jìn)去。下面展示了容器的 package.json 查找本文示例應(yīng)用的方法:

  1.  "name""@feed-me/container"
  2.  "version""1.0.0"
  3.  "description""A food delivery web app"
  4.  "dependencies": { 
  5.  "@feed-me/browse-restaurants""^1.2.3"
  6.  "@feed-me/order-food""^4.5.6"
  7.  "@feed-me/user-profile""^7.8.9" 
  8.  } 

這種辦法初看上去挺不錯。它通常會生成一個可部署的 Javascript 包,允許我們從各種應(yīng)用中刪除常見的重復(fù)依賴。但這意味著我們修改產(chǎn)品的任何部分時都必須重新編譯和發(fā)布所有微前端。這種 齊步走的發(fā)布流程 在微服務(wù)里已經(jīng)夠讓我們好受了,所以我們強(qiáng)烈建議不要用它來實現(xiàn)微前端架構(gòu)。我們好不容易在開發(fā)和測試階段實現(xiàn)了解耦和獨立,可別再在發(fā)布階段又繞回去了。我們得在運行時中也集成微前端。

通過 iframe 在運行時集成

想要在瀏覽器中組合應(yīng)用,一種最簡單的方法就是用 iframe。iframe 可以輕松地用一系列獨立的子頁面構(gòu)建整個頁面。它們的樣式和全局變量也能充分隔離,不會互相干擾。

  1. <html> 
  2.  <head> 
  3.  <title>Feed me!</title> 
  4.  </head> 
  5.  <body> 
  6.  <h1>Welcome to Feed me!</h1> 
  7.  <iframe id="micro-frontend-container"></iframe> 
  8.  <script type="text/javascript"
  9.  const microFrontendsByRoute = { 
  10.  '/''https://browse.example.com/index.html'
  11.  '/order-food''https://order.example.com/index.html'
  12.  '/user-profile''https://profile.example.com/index.html'
  13.  }; 
  14.  const iframe = document.getElementById('micro-frontend-container'); 
  15.  iframe.src = microFrontendsByRoute[window.location.pathname]; 
  16.  </script> 
  17.  </body> 
  18. </html> 

就像前文提到的服務(wù)器端包含方法一樣,用 iframe 構(gòu)建頁面并不是一種激動人心的新技術(shù)。但只要我們能精心分割好應(yīng)用并組建好團(tuán)隊,那么用 iframe 就能實現(xiàn)前面提到的一系列好處。

很多人不喜歡 iframe,它也的確有一些缺陷。上面提到的簡單隔離方式確實降低了它的靈活性。用 iframe 在應(yīng)用的各個部分之間構(gòu)建集成可能會很困難,從而讓路由、歷史記錄和深層鏈接變得更加復(fù)雜;它還會影響頁面的響應(yīng)速度。

通過 JavaScript 在運行時集成

這個方法非常靈活,應(yīng)用廣泛。每個微前端都使用<script>標(biāo)記包含在頁面上,并在加載時暴露全局函數(shù)作為其入口點。接下來容器應(yīng)用決定應(yīng)該加載哪個微前端,并調(diào)用相關(guān)函數(shù)來告訴微前端該何時何地呈現(xiàn)自己。

  1. <html> 
  2.  <head> 
  3.  <title>Feed me!</title> 
  4.  </head> 
  5.  <body> 
  6.  <h1>Welcome to Feed me!</h1> 
  7.  <!-- These scripts don't render anything immediately --> 
  8.  <!-- Instead they attach entry-point functions to `window` --> 
  9.  <script src="https://browse.example.com/bundle.js"></script> 
  10.  <script src="https://order.example.com/bundle.js"></script> 
  11.  <script src="https://profile.example.com/bundle.js"></script> 
  12.  <div id="micro-frontend-root"></div> 
  13.  <script type="text/javascript"
  14.  // These global functions are attached to window by the above scripts 
  15.  const microFrontendsByRoute = { 
  16.  '/': window.renderBrowseRestaurants, 
  17.  '/order-food': window.renderOrderFood, 
  18.  '/user-profile': window.renderUserProfile, 
  19.  }; 
  20.  const renderFunction = microFrontendsByRoute[window.location.pathname]; 
  21.  // Having determined the entry-point function, we now call it, 
  22.  // giving it the ID of the element where it should render itself 
  23.  renderFunction('micro-frontend-root'); 
  24.  </script> 
  25.  </body> 
  26. </html> 

上面是一個簡單的示例,展示了基本的技巧。相比構(gòu)建時集成,這里我們可以獨立部署各個 bundle.js 文件。相比 iframe,我們在構(gòu)建微前端之間的集成時有充分的靈活度。我們可以用多種方式擴(kuò)展上述代碼,例如按需下載各個 JavaScript 包,或者在呈現(xiàn)微前端時傳遞出入數(shù)據(jù)。

這種方法同時具備靈活性與獨立可部署能力,是我們的***方案。后文將詳細(xì)探討這個方法。

通過 Web 組件在運行時集成

之前方法的一個變體是為每個微前端定義用于容器實例化的 HTML 自定義元素,而非定義要調(diào)用的容器的全局函數(shù)。

  1. <html> 
  2.  <head> 
  3.  <title>Feed me!</title> 
  4.  </head> 
  5.  <body> 
  6.  <h1>Welcome to Feed me!</h1> 
  7.  <!-- These scripts don't render anything immediately --> 
  8.  <!-- Instead they each define a custom element type --> 
  9.  <script src="https://browse.example.com/bundle.js"></script> 
  10.  <script src="https://order.example.com/bundle.js"></script> 
  11.  <script src="https://profile.example.com/bundle.js"></script> 
  12.  <div id="micro-frontend-root"></div> 
  13.  <script type="text/javascript"
  14.  // These element types are defined by the above scripts 
  15.  const webComponentsByRoute = { 
  16.  '/''micro-frontend-browse-restaurants'
  17.  '/order-food''micro-frontend-order-food'
  18.  '/user-profile''micro-frontend-user-profile'
  19.  }; 
  20.  const webComponentType = webComponentsByRoute[window.location.pathname]; 
  21.  // Having determined the right web component custom element type, 
  22.  // we now create an instance of it and attach it to the document 
  23.  const root = document.getElementById('micro-frontend-root'); 
  24.  const webComponent = document.createElement(webComponentType); 
  25.  root.appendChild(webComponent); 
  26.  </script> 
  27.  </body> 
  28. </html> 

最終結(jié)果與前面的示例很像,主要區(qū)別在于這里以“Web 組件方式”操作。如果你喜歡 Web 組件規(guī)范,喜歡使用瀏覽器提供的功能,那么這也是個不錯的選擇。如果你更喜歡在容器應(yīng)用和微前端之間定義自己的接口,那么前面的示例可能更合適。

樣式

CSS 本質(zhì)上是一種全局、繼承和級聯(lián)的語言,傳統(tǒng) CSS 也沒有模塊系統(tǒng)、命名空間或封裝;有些功能現(xiàn)在也可用了,但往往缺乏瀏覽器支持。在微前端領(lǐng)域,這些問題往往變得更為嚴(yán)重。例如,如果一個團(tuán)隊的微前端有一個樣式表,上面寫著 h2 { color: black; },另一個微前端的樣式表卻寫著 h2 { color: blue; },并且這兩個選擇器都附加到了同一個頁面,后果就很嚴(yán)重了!這類問題古已有之,但在微前端體系中由于這些選擇器是由不同團(tuán)隊在不同時間編寫的,而且代碼可能分散在不同的存儲庫中,所以就更難發(fā)現(xiàn)了。

多年來業(yè)界發(fā)明了很多方法來更好地管理 CSS。有些人會使用嚴(yán)格的命名約定(例如 BEM 規(guī)范:http://getbem.com/)以確保選擇器只在正確的位置起作用。還有人會使用 SASS(https://sass-lang.com/)之類的預(yù)處理器,其嵌套的選擇器可以用作一種命名空間。一種較新的方法是使用 CSS 模塊或某種 CSS-in-JS 庫(詳見下方鏈接),以編程方式應(yīng)用所有樣式,確保樣式只會直接應(yīng)用在開發(fā)者想要的位置上。此外還有 shadow DOM(詳見下方鏈接),它也提供樣式隔離。

具體用哪種方法并不重要,只要讓開發(fā)者可以獨立編寫樣式,然后各個樣式集成到同一個應(yīng)用中時不起沖突就行了。

共享組件庫

前文提到微前端的視覺一致性是很重要的。一種實現(xiàn)方法是開發(fā)一個共享的、可重用的 UI 組件庫。創(chuàng)建這樣一個庫的主要好處是通過重用代碼和來減少工作量,同時實現(xiàn)視覺一致性。此外,這個組件庫可以當(dāng)作樣式指南來用,它可以是開發(fā)者和設(shè)計人員之間的一個很好的協(xié)作橋梁。

但最容易犯的一個錯誤就是過早地搞出來一大堆組件。我們都想創(chuàng)建一個基礎(chǔ)框架,其中包含所有應(yīng)用所需的所有常見視覺效果。但其實我們很難提前判斷組件應(yīng)該用什么 API,結(jié)果很多組件都是在白費功夫。所以我們更愿意讓團(tuán)隊在需要的時候再去創(chuàng)建自己的組件,就算因此產(chǎn)生了一些重復(fù)工作也沒關(guān)系。應(yīng)該順其自然,等組件的 API 都確定下來以后再把重復(fù)代碼收集到共享庫里,這樣就不會徒勞無功了。

最常見的共享組件是“無聲”的視覺基本元素,如圖標(biāo)、標(biāo)簽和按鈕等。我們還可以共享可能包含大量 UI 邏輯的復(fù)雜組件,例如自動完成、下拉搜索字段等;或者是可排序、可過濾的分頁表。但是,請確保共享組件僅包含 UI 邏輯,而不包含業(yè)務(wù)或域邏輯。將域邏輯放入共享庫會給應(yīng)用之間帶來高度耦合,改動起來也更困難。例如,一般來說不該共享 ProductTable,因為它會包含關(guān)于“產(chǎn)品”的定義及表現(xiàn)的各種內(nèi)容。這種域建模和業(yè)務(wù)邏輯應(yīng)該屬于微前端的應(yīng)用代碼,不應(yīng)該放到共享庫里。

作為一種內(nèi)部共享庫來說,它的所有權(quán)和管理也自然存在一些棘手的問題。一種管理模式是將其視為共享資產(chǎn),讓“每個人”都擁有它——實踐中這通常意味著沒人能真正擁有它。這個共享庫很快就會變成一堆不一致的代碼集合,也沒有明確的約定或技術(shù)愿景。反過來說,如果共享庫的開發(fā)工作完全中心化,那么組件的創(chuàng)建者與使用者之間就會嚴(yán)重脫節(jié)。***的模式應(yīng)該是允許所有人為庫做貢獻(xiàn),但要有一個保管人(一個人或一個團(tuán)隊)負(fù)責(zé)確保這些貢獻(xiàn)的質(zhì)量、一致性和有效性。維護(hù)共享庫需要強(qiáng)大的技術(shù)技能,還需要能協(xié)調(diào)眾多團(tuán)隊的管理技能。

跨應(yīng)用通信

關(guān)于微前端最常見的一個問題是如何讓這些微前端互相通信。一般來說,我們建議盡可能減少這類通信需求,因為它通常會重新引入我們本想避免的耦合度。

換句話說,某種程度的跨應(yīng)用通信是必要的。自定義事件(詳見下方鏈接)允許微前端之間間接通信,從而盡量減少直接耦合;但它也會讓各個微前端之間已有的合約更難確定和增強(qiáng)。另一種方法是將回調(diào)和數(shù)據(jù)向下傳遞的 React 模型(這里是從容器應(yīng)用向下傳遞到微前端),它能讓模塊之間的合約更加明確。第三種方法是使用地址欄作為通信機(jī)制,我們將在后面詳細(xì)介紹。

如果你在使用 redux,常見方案是為整個應(yīng)用提供單個全局共享存儲。但如果每個微前端都是自包含的應(yīng)用,那么它們都應(yīng)該有自己的 redux 存儲。Redux 文檔甚至給出了“在大型應(yīng)用中將 Redux 應(yīng)用隔離為組件”的說明。

無論選擇哪種方法,我們都希望微前端可以彼此發(fā)送消息或事件來通信,同時避免任何共享狀態(tài)。就像在微服務(wù)之間共享數(shù)據(jù)庫一樣,一旦我們共享了數(shù)據(jù)結(jié)構(gòu)和域模型就會引入大量的耦合,改動起來也會更困難。

這里也有幾種不錯的方案選項。最重要的是要時刻考慮你正在引入怎樣的耦合,以及如何持續(xù)維持模塊之間的合約。就像微服務(wù)之間的集成一樣,你需要在不同應(yīng)用和團(tuán)隊之間協(xié)調(diào)升級流程,才能對集成做出重大改動。

你還應(yīng)該考慮如何自動驗證集成的工作狀態(tài)。一種方法是功能測試,但它們的實施和維護(hù)成本很高?;蛘吣憧梢詫崿F(xiàn)某種形式的消費者驅(qū)動合約(詳見下方鏈接),這樣一來,無需在瀏覽器中集成全部微前端并運行應(yīng)用,就能讓每個微前端確定其他微前端需要哪些內(nèi)容。

后端通信

前端應(yīng)用開發(fā)倒是分配給各個獨立團(tuán)隊了,可后端呢?這里就是全棧團(tuán)隊的價值所在了,他們從可視代碼到 API 開發(fā)及數(shù)據(jù)庫和基礎(chǔ)架構(gòu)代碼都能自己搞定。有一種不錯的模式叫 BFF 模式,其中每個前端應(yīng)用都有一個對應(yīng)的后端,后者只用來滿足前者的需求。

這里有很多變量需要考慮。BFF 可能是自包含的,具有自己的業(yè)務(wù)邏輯和數(shù)據(jù)庫,或者它可能只是下游服務(wù)的聚合器。負(fù)責(zé)微前端及其 BFF 的團(tuán)隊是否應(yīng)該負(fù)責(zé)一部分下游服務(wù)也是個問題。如果微前端只有一個與之對話的 API,并且該 API 相當(dāng)穩(wěn)定,那么可能就不用構(gòu)建 BFF 了。這里的指導(dǎo)原則是,構(gòu)建某個微前端的團(tuán)隊不應(yīng)該依賴其他團(tuán)隊為他們構(gòu)建內(nèi)容。因此,如果每個添加到微前端的新功能都需要改動后端,那么讓同一個團(tuán)隊負(fù)責(zé) BFF 就很合適了。 

大前端時代下的微前端架構(gòu):增量升級、代碼解耦、獨立部署

另一個常見問題是,如何通過服務(wù)器對微前端應(yīng)用的用戶進(jìn)行身份驗證和授權(quán)操作?顯然,客戶應(yīng)該只需進(jìn)行一次身份驗證過程,因此身份驗證往往是跨領(lǐng)域問題,應(yīng)該由容器應(yīng)用負(fù)責(zé)。容器可能有某種登錄形式,我們通過它獲得某種令牌。該令牌將由容器控制,并且可以在初始化時注入各個微前端。***,微前端可以把令牌及其發(fā)送的請求發(fā)給服務(wù)器,而服務(wù)器可以按需完成驗證操作。

測試

在測試方面,單體前端和微前端之間沒有太大區(qū)別。一般來說在單體前端上使用的測試策略都能用在各個微前端上;也就是說每個微前端都應(yīng)該有自己的自動化全面測試套件,以確保代碼的質(zhì)量和正確性。

不一樣的是各種微前端與容器應(yīng)用的集成測試。可以使用你最喜歡的功能 / 端到端測試工具(例如 Selenium 或 Cypress)來做這部分測試;應(yīng)該使用單元測試來覆蓋你的低級業(yè)務(wù)邏輯和呈現(xiàn)邏輯,然后使用功能測試來驗證頁面是否正確組裝。例如,你可以在特定 URL 上加載完全集成的應(yīng)用,并用硬編碼標(biāo)題來在頁面上聲明相關(guān)的微前端。

如果有跨越不同微前端的用戶操作,那么就可以使用功能測試來覆蓋它們。但記住功能測試的重點是驗證前端的集成,而非每個微前端的內(nèi)部業(yè)務(wù)邏輯,后者應(yīng)該已經(jīng)被單元測試覆蓋了。如上所述,消費者驅(qū)動的合同可以用來直接指定微前端之間的交互,而不會破壞集成環(huán)境和功能測試。

責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2020-05-14 11:17:51

前端開發(fā)技術(shù)

2020-03-06 10:36:21

JavaScriptCSSHTML

2020-11-20 15:22:32

架構(gòu)運維技術(shù)

2023-11-20 08:12:15

2022-10-17 15:21:18

2022-08-19 14:06:56

前端架構(gòu)技術(shù)

2020-10-18 12:00:27

前端開發(fā)架構(gòu)

2017-11-15 09:32:27

解耦戰(zhàn)術(shù)架構(gòu)

2018-04-18 08:47:17

Alluxio構(gòu)建存儲

2021-05-18 09:48:58

前端開發(fā)架構(gòu)

2017-11-06 07:01:04

2024-04-18 00:26:14

AI模型語言

2024-04-28 00:00:00

前端代碼Vue

2022-08-10 06:52:28

RabbitMQ消息中間件

2023-04-28 07:41:38

Unity前端架構(gòu)

2019-01-17 10:58:37

2017-12-26 15:52:31

MQ互聯(lián)網(wǎng)耦合

2023-12-06 07:36:27

前端開發(fā)

2020-10-08 18:20:54

前端后端架構(gòu)

2012-07-10 01:47:14

代碼架構(gòu)設(shè)計
點贊
收藏

51CTO技術(shù)棧公眾號