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

呂立青發表於2017-12-27

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

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

歡迎關注我的部落格知乎GitHub


文章大綱

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

微前端的緣由:單體應用與微服務架構

The Majestic Monolith

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

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

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

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

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

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

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

從而微服務架構允許企業更自發地採取更深遠的業務決策,因為每個微服務都是獨立運作的,而且每一個管理團隊可以很好地控制該服務的變更。

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

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

在前端,往往由一個前端團隊建立並維護一個 Web 應用程式,使用 REST API 從後端服務獲取資料。這種方式如果做得好的話,它能夠提供優秀的使用者體驗。但主要的缺點是單頁面應用(SPA)不能很好地擴充套件和部署。在一個大公司裡,單前端團隊可能成為一個發展瓶頸。隨著時間的推移,往往由一個獨立團隊所開發的前端層越來越難以維護。

特別是一個特性豐富、功能強大的前端 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 1、Angular 2、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:微前端 - 將微服務理念擴充套件到前端開發 - 呂立青的部落格

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

相關文章