透過微前端升級 React
原文由 Alex O'Callaghan 于 發布,訂閱此部落格
2021 年,我們使用 React 17 部署了微前端架構。我們依循建議,將 react 和 react-dom 設為共用的 singleton 模組,讓整個應用程式在單一的 React 樹中渲染。隨著許多熱門相依套件開始要求 React 18,加上即將到來的 React 19,我們必須在微前端中升級 React。由於涉及眾多團隊,我們必須分階段逐步進行。
引進橋接元件
2026 年更新:我們後來將自行開發的微前端 React 橋接套件開源,詳情請見開源我們的微前端 React 橋接套件一文。本文介紹的是我們初期使用 @module-federation/bridge-react 套件的做法。
為了讓微前端在獨立的 React 樹中渲染,我們加入了一個「橋接」元件包裝層。這讓我們能在不影響 shell 的情況下,在微前端中升級 React。
@module-federation/bridge-react 套件提供了一些輔助工具來支援這種做法。在微前端中,我們新增了一個 export-app.tsx 檔案,將進入點的 React 元件用橋接包裝起來:
// src/export-app.tsx
import { createBridgeComponent } from "@module-federation/bridge-react";
import App from "./App";
export default createBridgeComponent({
rootComponent: App,
});
export const BRIDGE = true;我們也需要更新 ModuleFederationPlugin,以暴露這個新的進入點檔案。為了升級到比 shell 更新的版本,我們必須停止將 react 和 react-dom 作為 singleton 共用。
// webpack.config.js
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: "app",
filename: "remoteEntry.js",
exposes: {
"./App": "./src/export-app",
},
shared: ["react", "react-dom"],
}),
],
};在我們的 shell 應用程式中,我們使用 import-remote 來動態載入 remoteEntry 檔案。為了維持向下相容,我們需要調整這段邏輯,使其同時能載入直接暴露與經過橋接的 React 元件:
import { createRemoteComponent } from '@module-federation/bridge-react';
const SomeRemote = React.lazy(async () => {
const remote = await importRemote({
url: '/bundles/remote-app',
scope: 'remote-app',
module: 'App',
});
if (remote.BRIDGE) {
return {
default: createRemoteComponent({
loader: () => remote,
loading: <div>Loading...</div>,
fallback: (info) =>
<div>Failed to load {info.error.message}</div>,
});
}
return remote;
}
});這裡有幾個重點:
- 我們使用
importRemote來延遲載入remoteEntry.js檔案。這可以避免載入不必要的微前端。 - 我們檢查一個匯出的常數
BRIDGE。它會告訴我們該微前端是否已用橋接元件包裝。這讓各團隊可以自行選擇是否採用橋接,同時保持對尚未遷移者的相容性。 - 我們將橋接元件放在帶有
default屬性的物件中回傳,以模擬React.lazy預期接收的動態載入模組的結構。
這些變更讓我們得以將個別的微前端升級到 React 18,而無需升級 shell。一旦所有微前端都採用橋接的做法,我們就可以在不需要升級微前端的情況下升級 shell。
隨機一篇部落格
留言
登入後參與討論