Webpack 5模块联邦实战:微前端架构下跨应用共享组件配置方案

微前端架构解决单体前端应用膨胀后的维护困境,Webpack 5引入的模块联邦(Module Federation)允许独立构建的应用在运行时共享组件和模块,无需npm包发布即可实现跨应用代码复用。本文围绕模块联邦的Host与Remote配置、共享依赖管理、跨应用路由集成展开实战配置。

模块联邦核心概念与架构设计

模块联邦包含两个核心角色:

  • Host(消费者):运行时加载Remote暴露的模块,是页面的主入口应用
  • Remote(提供者):通过expose声明可被其他应用消费的模块

一个应用可以同时作为Host和Remote,形成网状共享拓扑。模块联邦的核心优势在于运行时动态加载,独立部署的子应用修改后无需重新构建Host。

典型微前端架构场景:主门户应用作为Host,业务子系统(用户管理、订单系统、数据分析)各自独立部署为Remote,主门户动态加载子系统的页面组件。

Remote应用暴露与共享依赖配置

Remote应用通过ModuleFederationPlugin声明暴露的模块:

// remote-app/webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
const deps = require('./package.json').dependencies;

module.exports = {
  output: {
    publicPath: 'http://localhost:3001/',
    uniqueName: 'remote_app',
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'remoteApp',
      filename: 'remoteEntry.js',
      exposes: {
        // 暴露的模块路径映射
        './UserDashboard': './src/components/UserDashboard',
        './OrderList': './src/components/OrderList',
        './utils': './src/utils/shared-utils',
      },
      shared: {
        react: { 
          singleton: true, 
          requiredVersion: deps.react,
          eager: false 
        },
        'react-dom': { 
          singleton: true, 
          requiredVersion: deps['react-dom'] 
        },
        antd: {
          singleton: true,
          requiredVersion: deps.antd,
        },
      },
    }),
  ],
};

shared配置的关键参数:

  • singleton:设为true确保全局只加载一份实例,React等库必须设为true
  • requiredVersion:指定版本范围,版本不兼容时触发额外加载
  • eager:设为true时模块不异步加载,适合共享入口文件

Remote应用入口文件需要异步加载以确保共享模块初始化:

// remote-app/src/index.js
import('./bootstrap');
// remote-app/src/bootstrap.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Host应用配置与远程模块加载

Host应用声明需要消费的Remote模块:

// host-app/webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
const deps = require('./package.json').dependencies;

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'hostApp',
      remotes: {
        remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js',
      },
      shared: {
        react: { singleton: true, requiredVersion: deps.react },
        'react-dom': { singleton: true, requiredVersion: deps['react-dom'] },
        antd: { singleton: true, requiredVersion: deps.antd },
      },
    }),
  ],
};

在Host应用中使用React.lazy加载远程组件:

// host-app/src/App.jsx
import React, { Suspense, lazy } from 'react';
import { Spin } from 'antd';

// 动态加载Remote暴露的组件
const UserDashboard = lazy(() => import('remoteApp/UserDashboard'));
const OrderList = lazy(() => import('remoteApp/OrderList'));

const LoadingFallback = () => (
  <div style={{ padding: 50, textAlign: 'center' }}>
    <Spin size="large" />
  </div>
);

function App() {
  return (
    <div>
      <Suspense fallback={<LoadingFallback />}>
        <UserDashboard />
      </Suspense>
      <Suspense fallback={<LoadingFallback />}>
        <OrderList />
      </Suspense>
    </div>
  );
}

export default App;

Host应用入口同样需要异步引导:

// host-app/src/index.js
import('./bootstrap');

跨应用路由集成与状态共享方案

微前端架构下路由管理需要在Host与Remote之间协调。Host管理顶层路由,Remote管理子路由:

// host-app/src/App.jsx — 路由配置
import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Layout />}>
          <Route index element={<Home />} />
          <Route path="/users/*" element={<UserModule />} />
          <Route path="/orders/*" element={<OrderModule />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

// Remote内部使用子路由
function UserModule() {
  return (
    <Suspense fallback={<LoadingFallback />}>
      <UserDashboard />
    </Suspense>
  );
}

跨应用状态共享通过模块联邦暴露store实例实现。Remote应用暴露Redux或Zustand store:

// remote-app暴露store
exposes: {
  './store': './src/store',
}

// host-app消费
const remoteStore = lazy(() => import('remoteApp/store'));

或者采用事件总线模式,各子应用通过自定义EventTarget或mitt库进行通信,保持应用解耦。

构建优化与生产环境部署配置

生产环境部署时需配置CDN域名与缓存策略:

// 生产环境webpack配置
output: {
  publicPath: 'https://cdn.example.com/remote-app/',
  filename: '[name].[contenthash].js',
  chunkFilename: '[name].[contenthash].js',
}

// remoteEntry.js配置长期缓存
new ModuleFederationPlugin({
  filename: 'remoteEntry.js',
  // remoteEntry.js本身不hash,保证Host引用路径不变
})

部署Remote应用时,只需将remoteEntry.js及其依赖的chunk上传至CDN,Host应用无需重新构建即可加载最新版本的Remote组件。通过Nginx配置remoteEntry.js的Cache-Control为短缓存或no-cache,确保Remote更新及时生效。

公共依赖提取策略:将react、react-dom等高频共享库配置为external或CDN加载,避免每个Remote重复打包,减少运行时下载体积。shared配置中singleton为true的模块只加载一次,后续Remote使用同一实例。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/webpack5-mo-kuai-lian-bang-shi-zhan-wei-qian-duan-jia-gou/

(0)
小编小编
上一篇 1天前
下一篇 1天前

相关推荐