微前端架构解决单体前端应用膨胀后的维护困境,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/