技術雷達之「微前端」- 將微服務理念擴展到前端開發 | 《前端的逆襲》知乎專欄

本文首發於技術雷達之「微前端」- 將微服務理念擴展到前端開發javascript

歡迎關注知乎專欄 —— 前端的逆襲css

歡迎關注個人博客知乎GitHubhtml


文章大綱

本文共計約 7k 字,預計閱讀時間 15mins前端

微前端的原因:單體應用與微服務架構

The Majestic Monolith

在傳統的軟件開發當中,大多數軟件都是單體式應用架構的。在瞬息萬變的商業時代背景下,企業必須學會適應咱們這個時代的不肯定性。快速試驗,快速失敗。更快地推出新產品和有效地改進當前產品,從而爲客戶提供有意義的數字體驗。vue

而單體應用這種軟件架構對於企業來講的致命缺點就是,企業對於市場的響應速度變慢。企業決策者在一年內須要作的決策數量很是有限,因爲依賴關係,其響應週期每每會變得很是漫長。每當開發或升級產品,都須要在一系列體量龐大的相關服務中同時增長新功能,這就須要全部利益相關方共同努力,以同步方式進行變動。java

微服務架構帶來了哪些好處?

假設服務邊界已經被正確地定義爲可獨立運行的業務領域,並確保在微服務設計中遵循諸多最佳實踐。那麼至少會如下幾個方面得到顯而易見的好處:react

  • 複雜性:服務能夠更好地分離,每個服務都足夠小,完成完整的定義清晰的職責;
  • 擴展性:每個服務能夠獨立橫向擴展以知足業務伸縮性,並資源的沒必要要消耗;
  • 靈活性:每個服務能夠獨立失敗,容許每一個團隊決定最適合他們的技術和基礎架構;
  • 敏捷性:每個服務均可以獨立開發,測試和部署,並容許團隊擴展獨立部署和維護服務的交付。

每一個微服務是孤立的,獨立的「模塊」,它們共同爲更高的邏輯目的服務。微服務之間經過 Contract 彼此溝通,每一個服務都負責特定的功能。這使得每一個服務都可以保持簡單,簡潔和可測試性。git

從而微服務架構容許企業更自發地採起更深遠的業務決策,由於每一個微服務都是獨立運做的,並且每個管理團隊能夠很好地控制該服務的變動。github

那麼前端的現狀呢? —— 臃腫的前端

在前端,每每由一個前端團隊建立並維護一個 Web 應用程序,使用 REST API 從後端服務獲取數據。這種方式若是作得好的話,它可以提供優秀的用戶體驗。但主要的缺點是單頁面應用(SPA)不能很好地擴展和部署。在一個大公司裏,單前端團隊可能成爲一個發展瓶頸。隨着時間的推移,每每由一個獨立團隊所開發的前端層愈來愈難以維護。web

特別是一個特性豐富、功能強大的前端 Web 應用程序,卻位於後端微服務架構之上。而且隨着業務的發展,前端變得愈來愈臃腫,一個項目可能會有 90% 的前端代碼,卻只有很是薄的後端,甚至這種狀況在 Serverless 架構的背景下還會愈演愈烈。

微前端的定義 - 將微服務理念擴展到前端開發

微前端(Micro Frontends)這個術語其實就是微服務的衍生物。將微服務理念擴展到前端開發,同時構建多個徹底自治的和鬆耦合的 App 模塊(服務),其中每一個 App 模塊只負責特定的 UI 元素和功能。

若是咱們看到微服務提供給後端的好處,那麼就能夠更進一步將這些好處應用到前端。與此同時,在設計微服務的時候,就能夠考慮不只要完成後端邏輯,並且還要完成前端的視覺部分。而對於微前端來講,與微服務的許多要求也是一致的:監控、日誌、HealthCheck、Analytics 等等。

拆分微前端所帶來的好處

這樣就能使各個前端團隊按照本身的步調迭代,並隨時準備就緒處於可發佈狀態,並隔離相互依賴所產生的風險,與此同時也更容易嘗試新技術。

  • Web 應用程序被分解成獨立的特徵,而且每一個特徵都由不一樣的團隊擁有,前端到後端。這確保了每一個功能都是獨立於其餘功能開發,測試和部署的。
  • 將網站或 Web 應用程序視爲由獨立團隊擁有的功能組合。每一個團隊都有一個獨特的業務或關注點肯定的任務。
  • 每個團隊是跨職能的,從數據庫到用戶界面端到端地開發其功能/特性。
  • 全部前端功能(身份驗證,庫存,購物車等)都是 Web 應用程序的一部分,並與後端(大部分時間經過 HTTP)進行通訊,並將其分解爲微服務。
  • 能夠同時擁有後端、前端、數據訪問層和數據庫,即一個服務子域所需的全部內容。
  • 查找線上 bug、測試、框架迭代,甚至語言、代碼隔離與責任和其餘事情變得更容易處理。
  • 咱們不得不付出的代價是部署,可是容器(Docker 和 Rocket)以及不可變服務器使得這種狀況也獲得了極大的改善。

微前端的核心思想

  • ✨ Be Technology Agnostic:每一個團隊都應該可以選擇和升級他們的技術棧,而沒必要與其餘團隊協調。自定義元素(後面會具體提到)是隱藏實現細節的好方法,同時爲其餘人提供公共接口。
  • ✨ Isolate Team Code:即便全部團隊使用相同的框架,也不要共享運行時。構建獨立的應用程序。不要依賴共享狀態或全局變量。
  • ✨ Establish Team Prefixes:相互約定命名隔離。爲 CSS、瀏覽器事件、Local Storage 和 Cookies 制定命名空間,以免衝突和明確其全部權。
  • ✨ Favor Native Browser Features over Custom APIs:使用瀏覽器事件進行通訊,而不是構建全局的 PubSub 系統。若是確實須要構建跨團隊 API,請儘可能保持簡單。(與框架無關,可以使用 CustomEvent)
  • ✨ Build a Resilient Site:即便 JavaScript 失敗或還沒有執行,Web 應用程序的功能仍應有效。可使用通用渲染和漸進加強來提升用戶的感知性能。

微前端的可選實踐方案(4 種+)

建立更小的 Apps(而不是 Components)

首先讓咱們來建立一個典型 Web 應用程序的基本組件(Header、ProductList、ShoppingCart),以 Header 組件爲例:

# src/App.js
export default () =>
  <header>
    <h1>Logo</h1>
    <nav>
      <ul>
        <li>About</li>
        <li>Contact</li>
      </ul>
    </nav>
  </header>;
複製代碼

而後須要注意的是咱們會用到 Express 對剛剛建立的 React 組件進行服務器端渲染,使之成爲一個 App 模塊:

# server.js
fs.readFile(htmlPath, 'utf8', (err, html) => {
  const rootElem = '<div id="root">';
  const renderedApp = renderToString(React.createElement(App, null));

  res.send(html.replace(rootElem, rootElem + renderedApp));
});
複製代碼

再依次建立其餘 Apps 並獨立部署:

如何組合微前端的 App 模塊?

在每一個獨立團隊建立好各自的 App 模塊後,咱們就能夠將網站或 Web 應用程序視爲由各類模塊的功能組合。下文將介紹多種技術實踐方案來從新組合這些模塊(有時做爲頁面,有時做爲組件),而前端(無論是否是 SPA)將只須要負責路由器(Router)如何選擇和決定要導入哪些模塊,從而爲最終用戶提供一致性的用戶體驗。

Option 1: 使用後端模板引擎插入 HTML

# server.js
Promise.all([
    getContents('https://microfrontends-header.herokuapp.com/'),
    getContents('https://microfrontends-products-list.herokuapp.com/'),
    getContents('https://microfrontends-cart.herokuapp.com/')
  ]).then(responses =>
    res.render('index', { header: responses[0], productsList: responses[1], cart: responses[2] })
  ).catch(error =>
    res.send(error.message)
  )
);
複製代碼
# views/index.ejs
  <head>
    <meta charset="utf-8">
    <title>Microfrontends Homepage</title>
  </head>
  <body>
    <%- header %>
    <%- productsList %>
    <%- cart %>
  </body>
複製代碼

可是,這種方案也存在弊端,即某些 App 模塊可能會須要相對較長的加載時間,而在前端整個頁面的渲染卻要取決於最慢的那個模塊。

好比說,可能 Header 模塊的加載速度要比其餘部分快得多,而 ProductList 則由於須要獲取更多 API 數據而須要更多時間。一般狀況下咱們但願儘快將網頁顯示給用戶,而在這種狀況下後臺加載時間就會變得更長。

Option 1.1: 漸進式從後端進行加載

固然,咱們也能夠經過修改一些後端代碼來漸進式地(Progressive)往前端發送 HTML,但與此同時卻徒增了後端複雜度,而且又將前端的渲染控制權交回了後端服務器。並且咱們的優化也取決於每一個模塊加載的速度,如果進行優化就必須按必定順序進行加載。

Option 2: 使用 IFrame 隔離運行時

<body>
  <iframe width="100%" height="200" src="https://microfrontends-header.herokuapp.com/"></iframe>
  <iframe width="100%" height="200" src="https://microfrontends-products-list.herokuapp.com/"></iframe>
  <iframe width="100%" height="200" src="https://microfrontends-cart.herokuapp.com/"></iframe>
</body>
複製代碼

咱們也能夠將每一個子應用程序嵌入到各自的 <iframe> 中,這使得每一個模塊可以使用任何他們須要的框架,而無需與其餘團隊協調工具和依賴關係,依然能夠藉助於一些庫或者 Window.postMessageAPI 來進行交互。

  • 優勢
    • 最強大的是隔離了組件和應用程序部分的運行時環境,所以每一個模塊均可以獨立開發,而且能夠與其餘部分的技術無關
    • 能夠各自使用徹底不一樣的前端框架,能夠在 React 中開發一部分,在 Angular 中開發一部分,而後使用原生 JavaScript 開發其餘部分或任何其餘技術。
    • 只要每一個 iframe 來自同一個來源,消息傳遞也就至關直接和強大。參考文檔 Window.postMessageAPI
  • 缺點
    • Bundle 的大小很是明顯,由於可能最終會屢次發送相同的庫,而且因爲應用程序是分開的,因此在構建時也不能提取公共依賴關係。
    • 至於瀏覽器的支持,基本上不可能嵌套兩層以上的 iframe(parent - > iframe - > iframe)。
    • 若是任何嵌套的框架須要可以滾動或具備 Form 表單域,那樣的狀況處理起來就會變得特別痛苦。

Option 3: 客戶端 JavaScript 異步加載

function loadPage (element) {
  [].forEach.call(element.querySelectorAll('script'), function (nonExecutableScript) {
    var script = document.createElement("script");
    script.setAttribute("src", nonExecutableScript.src);
    script.setAttribute("type", "text/javascript");
    element.appendChild(script);
  });
}

document.querySelectorAll('.load-app').forEach(loadPage);
複製代碼
<div class="load-app" data-url="header"></div>
<div class="load-app" data-url="products-list"></div>
<div class="load-app" data-url="cart"></div>
複製代碼

簡單來講,這種方式就是在客戶端瀏覽器經過 Ajax 加載應用程序,而後將不一樣模塊的內容插入到對應的 div 中,並且還必須手動克隆每一個 script 的標記才能使其工做。

須要注意的是,爲了不 Javascript 和 CSS 加載順序的問題,建議將其修改爲相似於 Facebook bigpipe 的解決方案,返回一個 JSON 對象 { html: ..., css: [...], js: [...] } 再進行加載順序的控制。

Option 4: WebComponents 整合全部功能模塊

Web Components 是一個 Web 標準,因此像 Angular、React/Preact、Vue 或 Hyperapp 這樣的主流 JavaScript 框架都支持它們。你能夠將 Web Components 視爲使用開放 Web 技術建立的可重用的用戶界面小部件,也許會是 Web 組件化的將來。

Web Components 由如下四種技術組成(儘管每種技術均可以獨立使用):

  • 自定義元素(Custom Elements)對外提供組件的標籤,實現自定義標籤:能夠建立本身的自定義 HTML 標籤和元素。每一個元素能夠有本身的腳本和 CSS 樣式。還包括生命週期回調,它們容許咱們定義正在加載的組件特定行爲。
  • HTML 模板(HTML <template>定義組件的 HTML 模板能力:一種用於保存客戶端內容的機制,該內容在頁面加載時不被渲染,但能夠在運行時使用 JavaScript 進行實例化。能夠將一個模板視爲正在被存儲以供隨後在文檔中使用的一個內容片斷。
  • 影子 DOM(Shadow DOM)封裝組件的內部結構,而且保持其獨立性:容許咱們在 Web 組件中封裝 JavaScript,CSS 和 HTML。在組件內部時,這些東西與主文檔的 DOM 分離。
  • HTML 導入(HTML Imports)解決組件組合和依賴加載:在微前端的上下文中,能夠是包含咱們要使用的組件在服務器上的遠程位置。
# src/index.js
class Header extends HTMLElement {
  attachedCallback() {
    ReactDOM.render(<App />, this.createShadowRoot());
  }
}
document.registerElement('microfrontends-header', Header);
複製代碼
<body>
    <microfrontends-header></microfrontends-header>
    <microfrontends-products-list></microfrontends-products-list>
    <microfrontends-cart></microfrontends-cart>
</body>
複製代碼

在微前端的實踐當中:

  • 每一個團隊使用各自的技術棧建立他們的組件,並把它包裝到自定義元素(Custom Element)中(如 <microfrontends-header></microfrontends-header>)。
  • Web 組件就是應用程序中包含的組件的本地實現,如菜單,表單,日期選擇器等。每一個組件都是獨立開發的,主應用程序項目利用它們組裝成最終的應用程序。
  • 特定元素(標籤名稱,屬性和事件)的 DOM 規範還能夠充當跨團隊之間的契約或公共 API。
  • 建立可被導入到 Web 應用程序中的可重用組件,它們就像能夠導入任何網頁的用戶界面小部件。
<link rel="import" href="/components/microfrontends/header.html">
<link rel="import" href="/components/microfrontends/products-list.html">
<link rel="import" href="/components/microfrontends/cart.html">
複製代碼
  • 優勢
    • 代碼的可讀性變得很是清晰,組件資源內部高內聚,組件資源由自身加載控制,做用域獨立。
    • 功能團隊可使用組件及其功能,而沒必要知道實現,他們只須要可以與 HTML DOM 進行交互。
    • 使用 PubSub 機制,組件能夠發佈消息,其餘組件能夠訂閱特定的主題。幸運的是瀏覽器內置了這個功能。好比購物車能夠在 window 訂閱此事件並在應該刷新其數據時獲得通知。
  • 缺點
    • 惋惜的是,Web 組件規範跟服務器渲染無關。沒有 JavaScript,就沒有所謂的自定義元素。
    • 瀏覽器和框架的支持不夠,須要更多的 polyfills 從而影響到用戶頁面的加載體驗。
    • 咱們須要在整個 Web 應用程序上作出改變,把它們所有轉換成 Web Components。
    • 社區不夠活躍,Web Components 尚未真正流行起來,也許永遠也不會。

不一樣 App 模塊之間如何交互?

# angularComponent.ts
const event = new CustomEvent('addToCart', { detail: item });
window.dispatchEvent(event);
複製代碼
# reactComponent.js
componentDidMount() {
  window.addEventListener('addToCart', (event) => {
    this.setState({ products: [...this.state.products, event.detail] });
  }, false);
}
複製代碼
  • 得益於瀏覽器的原生 API,Custom Event 能夠與其餘任何技術和框架一塊兒工做。好比,咱們能夠將消息從 Angular 組件發送到 React 組件。其實這也是如今 API 之間廣泛使用 JSON 進行通訊的緣由,即便沒有人使用 NodeJS 做爲服務器端。
  • 可是,新的問題又出現了。咱們該如何測試這種跨模塊之間的交互?須要編寫相似於後端微服務之間的 Contract Testing 或 Integration Testing 嗎?並無答案。

More Options...

  • 組件庫 - 根據主 App 的技術棧,不一樣的組件和 App 模塊拆分做爲庫的形式提供給主App,因此主 App 是由不一樣組件組成的。可是組件庫的升級將成爲一個大麻煩,好比對 Header 組件進行了更改,那麼若是已經有 50 個頁面使用了 Header 組件該怎麼辦?必需要求每一頁都升級它的 Header,並且升級過程當中用戶還會在整個網站不一樣頁面上看到不一致的標題。而且,在兩邊還必須都使用相同的技術,好比 Header 組件中使用了 ClojureScript,而 Content 組件中又用了 Elm,那麼該怎麼辦?構建工具就必須在編譯時處理不一樣的語言。
  • 將 App 模塊做爲 React 黑盒組件分發給消費者模塊 - 應用程序的狀態徹底包含在組件中,API 只是經過 props 暴露出來。這種方式其實增長了應用程序之間的耦合,由於它迫使每一個人都使用 React,甚至會使用相同版本的 React,可是這彷佛也是一個比較好的折衷。
  • Edge Side Includes(ESI)/Server Side Includes(SSI) - 經過特殊的文件後綴 (shtml,inc) 或簡單的標記語言來對那些能夠加速和不能加速的網頁中的內容片段進行描述,將每一個網頁劃分紅不一樣的小部分分別賦予不一樣的緩存控制策略。SSI / ESI 方法的缺點是,最慢的片斷決定了整個頁面的響應時間。

微前端的頁面優化與實例

多模塊頁面加載問題與優化建議

  • 使用 skeleton screen 響應式佈局:如上圖 LinkedIn 所作的那樣,首先展示給用戶一個頁面的空白版本,而後在這個頁面中逐漸加載和填充相應的信息。不然中間的信息流部分的內容最初是空白的,而後在 JavaScript 被加載和執行事後,信息流就會由於須要佔用更多的空間而推進整個頁面的佈局。雖然咱們能夠控制頁面來固定中間部分的高度,但在響應式網站上,肯定一個確切的高度每每很難,並且不一樣的屏幕尺寸可能會有所不一樣。但更重要的問題是,這種高度尺寸的約定會讓不一樣團隊之間產生緊密的聯繫,從而違背了微前端的初衷。
  • 使用瀏覽器異步加載加快初始渲染:對於加載成本高且難以緩存的碎片,將其從初始渲染中排除是一個好主意。好比說 LinkedIn 首頁的信息流就是一個很好的例子。
  • 共享 UI 組件庫保證視覺體驗一致:在前端設計中,必須向用戶呈現外觀和感受一致的用戶界面。建議能夠創建一個共享組件庫(包含 CSS、字體和 JavaScript)。將這些資源託管在 CDN,每一個微前端就能夠在其 HTML 輸出中引用它們的位置。每一個組件庫的版本都正確地對資源進行版本控制,而每一個微前端都指定要使用的組件庫的版本和顯式更新依賴關係。
  • 使用集中式服務(Router)來管理 URL:能夠理解爲前端的 Gateway,不一樣的 URL 對應不一樣應用程序所包含的內容。建議經過一個集中式的 URLs Router 來爲應用程序提供一個 API 來註冊他們本身的 URL,Router 將會位於 Web 應用程序的前面,根據不一樣的用戶請求指向不一樣的 App 模塊組合。

  • 提取共同依賴做爲 externals 加載:雖說不一樣 App 模塊之間不能直接共享相同的第三方模塊,當咱們依然能夠將經常使用的依賴好比 lodashmoment.js等公共庫,或者跨多個團隊共同使用的 reactreact-dom。經過 Webpack 等構建工具就能夠把打包的時候將這些共同模塊排除掉,而只須要在 HTML <header> 中的 <script>中直接經過 CDN 加載 externals 依賴。
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/react.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/react-dom.min.js" crossorigin="anonymous"></script>
複製代碼

微前端在 AEM(CMS)項目的應用

咱們在「三靠譜」(已和諧客戶名稱)的 Marketplace 項目當中也曾經探索過 AEM + React 混合開發的解決方案,其中就涉及到如何在 AEM 當中嵌入 React 組件,甚至將 AEM 組件又強行轉化爲 React 組件進行嵌套。如今回過頭來其實也算是微前端的一種實踐:

  • AEM 僅僅包含網頁內容,不包含 domain 相關的結構化數據。
  • React 組件被託管在 AEM 組件當中,再經由 AEM 傳遞給組件所須要的屬性,好比 IDs 或 APIs 的 URL 等等
  • 後端微服務則包含 domain 結構化數據,由對應的 React 組件經過 Ajax 進行數據查詢。
<div id="cms-container-1">
    <div id="react-input-container"></div>
    <script> ReactDOM.render(React.createElement(Input, { ...injectProps }), document.getElementById('react-input-container')); </script>
  </div>
  <div id="cms-container-2">
    <div id="react-button-container"></div>
    <script> ReactDOM.render(React.createElement(Button, {}), document.getElementById('react-button-container')); </script>
  </div>
複製代碼

現成解決方案:Single-SPA 「meta framework」

點擊圖片可查看實例

開源的 single-spa 自稱爲「元框架」,能夠實如今一個頁面將多個不一樣的框架整合,甚至在切換的時候都不須要刷新頁面(支持 React、Vue、Angular 一、Angular 二、Ember 等等):

  • Build micro frontends that coexist and can each be written with their own framework.
  • Use multiple frameworks on the same page without refreshing the page (React, AngularJS, Angular, Ember, or whatever you're using)
  • Write code using a new framework, without rewriting your existing app
  • Lazy load code for improved initial load time.
  • Hot reload entire chunks of your overall application (instead of individual files).

請看示例代碼,所提供的 API 很是簡單:

import * as singleSpa from 'single-spa';

const appName = 'app1';

const loadingFunction = () => import('./app1/app1.js');
const activityFunction = location => location.hash.startsWith('#/app1');

singleSpa.declareChildApplication(appName, loadingFunction, activityFunction);
singleSpa.start();
複製代碼
# single-spa-examples.js

declareChildApplication('navbar', () => import('./navbar/navbar.app.js'), () => true);
declareChildApplication('home', () => import('./home/home.app.js'), () => location.hash === "" || location.hash === "#");
declareChildApplication('angular1', () => import('./angular1/angular1.app.js'), hashPrefix('/angular1'));
declareChildApplication('react', () => import('./react/react.app.js'), hashPrefix('/react'));
declareChildApplication('angular2', () => import('./angular2/angular2.app.js'), hashPrefix('/angular2'));
declareChildApplication('vue', () => import('src/vue/vue.app.js'), hashPrefix('/vue'));
declareChildApplication('svelte', () => import('src/svelte/svelte.app.js'), hashPrefix('/svelte'));
declareChildApplication('preact', () => import('src/preact/preact.app.js'), hashPrefix('/preact'));
declareChildApplication('iframe-vanilla-js', () => import('src/vanillajs/vanilla.app.js'), hashPrefix('/vanilla'));
declareChildApplication('inferno', () => import('src/inferno/inferno.app.js'), hashPrefix('/inferno'));
declareChildApplication('ember', () => loadEmberApp("ember-app", '/build/ember-app/assets/ember-app.js', '/build/ember-app/assets/vendor.js'), hashPrefix('/ember'));

start();
複製代碼

總結與思考:微前端的優缺點

優勢

  • 敏捷性 - 獨立開發和更快的部署週期:
    • 開發團隊能夠選擇本身的技術並及時更新技術棧。
    • 一旦完成其中一項就能夠部署,而沒必要等待全部事情完畢。
  • 下降錯誤和迴歸問題的風險,相互之間的依賴性急劇降低。
  • 更簡單快捷的測試,每個小的變化沒必要再觸碰整個應用程序。
  • 更快交付客戶價值,有助於持續集成、持續部署以及持續交付。
  • 維護和 bugfix 很是簡單,每一個團隊都熟悉所維護特定的區域。

缺點

  • 開發與部署環境分離
    • 本地須要一個更爲複雜的開發環境。
    • 每一個 App 模塊有一個孤立的部署週期。
    • 最終應用程序須要在同一個孤立的環境中運行。
  • 複雜的集成
    • 須要考慮隔離 JS,避免 CSS 衝突,並考慮按需加載資源
    • 處理數據獲取並考慮用戶的初始化加載狀態
    • 如何有效測試,微前端模塊之間的 Contract Testing?
  • 第三方模塊重疊
    • 依賴冗餘增長了管理的複雜性
    • 在團隊之間共享公共資源的機制
  • 影響最終用戶的體驗
    • 初始 Loading 時間可能會增長
    • HTML 會須要服務器端的渲染

持續思考…

  • (變幻莫測)前端的技術選型?

    • 前端 JavaScript 框架工具窮出不窮,過幾個月就要重寫前端項目?好比最近又出來了聲稱要取代 Webpack(Parcel)和 Yarn(Turbo)的工具。伴隨着前端框架的更新換代,若是整個項目一塊兒升級/重構的話壓力大、風險高,那不如拆分微前端直接支持多 framework,或者同一 framework 的不一樣版本?
  • 在 Mobile/Mobile Web 上的悖論

    • 受限於 Mobile 尺寸大小,單一頁面所能展示的內容本就有限。
    • 既然已經分出了不一樣的子頁面,那何不如直接 Route 便可?
  • 合理劃分的邊界:DDD(領域驅動開發)

    • 最大的挑戰是搞清楚如何合理拆分應用程序。
    • 糟糕的設計可能成爲開發和維護的噩夢。
  • Don't use any of this if you don't need it

    • Do not use the ideas described here until it is needed, it will make things more complex.
    • If you are in a big company, those ideas could help you.
  • 軟件架構到底在解決什麼問題?—— 跨團隊溝通的問題

    • 在正常狀況下,每一個團隊擁有開發和維護其特性所需的一切,都應該有本身的能力來完成本身的特性,並最大限度地減小團隊要求其餘部門得到許可和/或幫助。
    • 當引入 library 或 framework 時的好處是隻須要少數人討論,而不用涉及超過 100 人的決策和他們的各類需求。這樣一場大討論不只會耗費時間和精力,並且會迫使咱們採用最不起眼的方法來選擇 library,而不是選擇專門針對每一個 team 的問題領域的方案。

    所謂架構,實際上是解決人的問題;所謂敏捷,實際上是解決溝通的問題;

參考資料

本次技術雷達「微前端」主題的宣講 Slides 能夠在個人博客找到:「技術雷達」之 Micro Frontends:微前端 - 將微服務理念擴展到前端開發 - 呂立青的博客

相關文章
相關標籤/搜索