Chuyển đến nội dung chính

第 12 課:Webpack 模組聯合與 Vite — 深入探討

從零開始實踐模組聯盟。配置主機/遠端應用程式。共享依賴管理。 Vite 聯邦外掛程式。錯誤邊界和後備策略。

🏗️ 建築 — 第 12 課 第 12 課:Webpack 模組聯合與 Vite — 深入探討

微服務與微前端系統設計-從基礎到生產

第 4 部分:微前端 — 架構與原理

亞洲開發網

簡介

Module Federation 是 Webpack 5 的一項改變遊戲規則的功能,允許多個構建在運行時共享代碼。本文從零開始動手配置。

Module Federation — Host & Remote runtime loading


1. 核心概念

概念描述
主持人應用程式載入遠端模組(Shell App)
遠端應用程式為主機公開模組 (MFE)
共享主機與遠端之間共享的依賴關係
remoteEntry.js清單檔案包含有關遠端模組的資訊
┌─────────────────────────────┐
│ Browser                     │
│  Shell App (Host)           │
│  ┌─────────────────────┐    │
│  │ import('product/    │────────► remoteEntry.js (CDN)
│  │   ProductList')     │    │     → chunk-abc.js
│  └─────────────────────┘    │
│  Shared: React 18.2.0       │
│  (loaded ONCE)              │
└─────────────────────────────┘

2. 主機設定(Shell App)

// webpack.config.js (Shell App)
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'shell',
      remotes: {
        product: 'product@https://product.cdn.com/remoteEntry.js',
        cart: 'cart@https://cart.cdn.com/remoteEntry.js',
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.2.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.2.0' },
      },
    }),
  ],
};

3.遠端設定(產品MFE)

// webpack.config.js (Product MFE)
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'product',
      filename: 'remoteEntry.js',
      exposes: {
        './ProductList': './src/components/ProductList',
        './ProductDetail': './src/components/ProductDetail',
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.2.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.2.0' },
      },
    }),
  ],
};

4. 在主機中使用

import React, { Suspense } from 'react';

const ProductList = React.lazy(() => import('product/ProductList'));
const MiniCart = React.lazy(() => import('cart/MiniCart'));

function App() {
  return (
    <div>
      <Header />
      <MFEErrorBoundary>
        <Suspense fallback={<div>Loading products...</div>}>
          <ProductList />
        </Suspense>
      </MFEErrorBoundary>
      <Footer />
    </div>
  );
}

5. 遠端 MFE 的錯誤邊界

class MFEErrorBoundary extends React.Component {
  state = { hasError: false };
  
  static getDerivedStateFromError() {
    return { hasError: true };
  }
  
  render() {
    if (this.state.hasError) {
      return <div>MFE unavailable. <button onClick={() => 
        this.setState({ hasError: false })}>Retry</button></div>;
    }
    return this.props.children;
  }
}

6. 共享依賴管理

shared: {
  react: {
    singleton: true,         // Chỉ load 1 version
    requiredVersion: '^18.2.0',
    eager: false,            // Lazy load (recommended)
    strictVersion: false,    // Cho phép minor version khác
  },
}

版本衝突解決:

Host: [email protected]
Remote A: [email protected]  → Dùng shared (Host's version)
Remote B: [email protected]  → singleton → dùng 18.2.0 (warning)
Remote C: [email protected]  → strictVersion=true → ERROR

7. Vite 模組聯盟

// vite.config.js (Remote)
import federation from '@originjs/vite-plugin-federation';

export default defineConfig({
  plugins: [
    react(),
    federation({
      name: 'product',
      filename: 'remoteEntry.js',
      exposes: {
        './ProductList': './src/components/ProductList',
      },
      shared: ['react', 'react-dom'],
    }),
  ],
});

總結

  • 模組聯合=獨立建置之間的執行時間程式碼共用
  • 主機透過以下方式載入遠端模組 remoteEntry.js
  • 共享依賴項:單例模式避免重複的 React
  • 生產所需的誤差邊界
  • Vite 透過外掛程式支持,類似語法

下一篇文章: 第 13 課:Shell 應用程式 — 路由、佈局和編排