iT邦幫忙

2024 iThome 鐵人賽

DAY 8
2

微前端的溝通

在微前端中,跨應用溝通是一個非常麻煩的事,你沒辦法像平時習慣的一個 “import” 語法來傳遞共用。那到底在微前端怎麼做跨應用溝通呢?

後端有 API,那前端呢?其實大部分我們可以認知的是走網路的 HTTP 協定 API,但其實廣義來說,API 這詞彙可以用在很多地方。微服務中,微前端仰賴 HTTP 協定建構 API 的溝通橋樑,那微前端呢?

API 原則

要能作為良好的 API,穩定性很重要。那擁有最穩定的 API,長期也不容易發生異動,跨專案與環境都可以很好的支援的就是原生 API,不管是走網路協定還是 Browser API 都是很好的選擇。然而要很謹慎的地方是不要依賴「狀態」來溝通,因為會有同步的問題,最理想是依靠著「傳遞」來達到溝通的目的。

微前端溝通的核心原理

其實我們可以知道,所有微前端其實都是運行在同一個 global 之下,所以只要在一樣的 global 就一定可以被溝通。

那這個 global 是誰?凡是在這個 website 下,singleton 的所有對象都可以是溝通媒介。舉凡,同一個 backend service 、同一個 window object、被定義為 singleton 的 object 都符合這個條件。

微前端溝通的解決方案

那有沒有具體方法呢?
其實我可以舉幾個常見的手法來說。

共用遠端模組

利用 module federation 共用同一包狀態管理器,不需要維護複雜的機,由它的內部機制來溝通。或是直接使用套件再共享也行,但要注意版本必須相同,否則記憶體就無法共用。

// A 應用,共享模組 store

const state = {};

const getState = () => {
  return state;
};
const setState = (property, value) => {
  state[property] = value;
};

export { getState, setState };
// B 應用
import { getState } from "app-a/store";

const state = getState();
// C 應用
import { setState } from "app-a/store";

setState("test", "value");

如果真的卡到版本問題,最理想還是要避免綁定在版本上,以解耦的機制來溝通最為保險。

瀏覽器事件

使用 browser 機制溝通。通過 EventTarget 來做事件派發,可以向 window, document … 等等物件來進行溝通。或是使用 broadcast channel, message event, service worker 等等方式觸發。搭配 localStorage, sessionStorage, cookie, … 等等方式進行資料傳遞。

// event-bus.js
const eventBus = {
  on: (type, callback) => {
    window.addEventListener(type, callback);
  },
  off: (type, callback) => {
    window.removeEventListener(type, callback);
  },
  emit: (type, detail) => {
    window.dispatchEvent(new CustomEvent(type, { detail }));
  },
};

基本上所有微前端建構的網頁依然在同一個 Document 下,所以依然能夠仰賴 DOM 的物件實體來達到溝通,甚至搭配冒泡機制取得事件的資訊。所以也可以用事件冒泡來取得事件觸發。

const emit = (dom, type, detail) => {
  dom.dispatchEvent(
    new CustomEvent(type, {
      detail,
      bubbles: true,
      cancelable: true,
      composed: true,
    })
  );
};
WebComponent

利用瀏覽器原生的 WebComponent 來溝通,它可以傳遞 attribute, event, slot template 等多種資訊,具備懶加載特性,可以說是非常彈性的解決方案。

class CustomComponent extends HTMLElement {
  // impl...
}
customElements.define("custom-component", CustomComponent);

關於更詳細的實作就不在這贅述,後面別的章節再詳細說明使用。

WebSocket

使用後端串接 WebSocket 來溝通,以後端作為溝通橋樑,將資料存在後端,並使用 WebSocket 進行事件觸發。

可以應用 HTTP Request + WebSocket,一樣採用網路手段來達到溝通,API 設計只需要可考慮 HTTP 手段,不需要額外學習溝通的手段。但問題在會消費一定的網路資源,而微前端只是在前端溝通,卻要追加這層流量的消費。

ServiceWork

在 ServiceWork 可以去攔截對外部發出的 HTTP 請求,就可以假裝提供了某個服務,能不向網路溝通就完成內部服務的自給自足。也可以作為「假裝是 Backend API」來提供服務,學習成本和直覺度都非常高,就像是真的在實作微服務一樣。

後記

以上我只是寫出一些常見有討論度的方法,以及自己在 POC 玩過的一些手段,其實微前端的溝通方式發揮一點創意還是能夠有很多作法。如果有其他你知道的方式,歡迎來跟我分享喔~


上一篇
(七) 微前端的模組共用
下一篇
(九) 全域單例狀態管理
系列文
前端也可以搞微服務?!前端最複雜的一種架構30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Dylan
iT邦新手 1 級 ‧ 2024-08-08 20:42:36

結尾是不是少了一些字😂

對啊~~
寫一寫就斷片了XD

我要留言

立即登入留言