微前端架构将大型单页应用拆分为独立部署的子应用,解决单体前端工程维护困难的问题。Webpack 5引入的Module Federation原生支持跨应用模块共享,无需额外框架即可实现远程模块动态加载。前端工程化实践中,Module Federation已成为构建可扩展微前端体系的关键技术方案。
Module Federation核心概念
Module Federation定义了两个角色:Host(消费者)和Remote(提供者)。Remote应用通过webpack配置暴露组件或模块,Host应用声明依赖并在运行时动态加载。多个应用可共享React、Vue等公共依赖,避免重复打包。
与single-spa等方案相比,Module Federation在构建层面实现模块共享,支持Tree-shaking和按需加载,且不依赖额外运行时框架。
Remote应用配置
创建一个独立的产品管理子应用,暴露ProductList组件和ProductService工具类:
// remote/webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
const deps = require('./package.json').dependencies;
module.exports = {
entry: './src/index.js',
mode: 'development',
devServer: {
port: 3001,
headers: { 'Access-Control-Allow-Origin': '*' },
},
output: {
publicPath: 'http://localhost:3001/',
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: { presets: ['@babel/preset-react'] },
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'productApp',
filename: 'remoteEntry.js',
exposes: {
'./ProductList': './src/components/ProductList',
'./ProductService': './src/services/ProductService',
},
shared: {
react: { singleton: true, requiredVersion: deps.react },
'react-dom': { singleton: true, requiredVersion: deps['react-dom'] },
},
}),
],
};
关键配置项说明:
name: 'productApp':远程应用标识,Host通过此名称引用filename: 'remoteEntry.js':暴露入口文件,Host加载此文件获取远程模块exposes:声明对外暴露的模块映射shared:共享依赖配置,singleton: true确保全局只加载一个React实例
Host应用配置与远程模块加载
// host/webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
const deps = require('./package.json').dependencies;
module.exports = {
devServer: { port: 3000 },
plugins: [
new ModuleFederationPlugin({
name: 'shellApp',
remotes: {
productApp: 'productApp@http://localhost:3001/remoteEntry.js',
},
shared: {
react: { singleton: true, requiredVersion: deps.react },
'react-dom': { singleton: true, requiredVersion: deps['react-dom'] },
},
}),
],
};
在Host应用中使用React.lazy动态加载远程组件,配合Suspense处理加载状态:
// host/src/App.jsx
import React, { Suspense, lazy } from 'react';
const ProductList = lazy(() => import('productApp/ProductList'));
function App() {
return (
<div>
<h1>主应用 - 控制台</h1>
<Suspense fallback={<div>加载产品模块...</div>}>
<ProductList />
</Suspense>
</div>
);
}
export default App;
Host入口文件需引入联邦运行时,确保共享依赖初始化:
// host/src/index.js
import('bootstrap.js');
// host/src/bootstrap.js
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
const root = createRoot(document.getElementById('root'));
root.render(<App />);
将入口拆分为index.js和bootstrap.js是Module Federation的必要步骤。webpack需要先加载联邦运行时再执行应用代码,否则共享依赖无法正确初始化。
共享依赖版本协商机制
多应用共享同一依赖时,Module Federation通过版本协商确定加载哪个版本。配置项控制协商行为:
shared: {
react: {
singleton: true, // 全局只加载一个实例
requiredVersion: '^18.0.0',
eager: false, // 异步加载共享依赖
strictVersion: false, // 允许使用不满足requiredVersion的版本
},
'react-dom': {
singleton: true,
requiredVersion: '^18.0.0',
},
lodash: {
eager: true, // 同步加载,不参与按需
singleton: false, // 允许多版本共存
},
}
版本协商规则:当singleton: true时,所有应用共享最高满足条件的版本;当strictVersion: true时,版本不匹配会抛出警告;eager: true表示依赖不参与异步加载,直接打包进chunk。
独立部署与动态Remote配置
生产环境中Remote应用独立部署到CDN,Host应用通过环境变量配置Remote地址。动态注册Remote避免硬编码URL:
// host/src/utils/loadRemote.js
const remoteRegistry = {
productApp: process.env.PRODUCT_APP_URL || 'https://cdn.example.com/product/remoteEntry.js',
userApp: process.env.USER_APP_URL || 'https://cdn.example.com/user/remoteEntry.js',
};
async function loadRemoteEntry(url, scope) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = url;
script.onload = () => {
const container = window[scope];
container.init(__webpack_share_scopes__.default);
resolve(container);
};
script.onerror = reject;
document.head.appendChild(script);
});
}
export async function importRemote(scope, module) {
const url = remoteRegistry[scope];
await loadRemoteEntry(url, scope);
const factory = await window[scope].get(module);
return factory();
}
使用动态加载函数替代静态import,运行时按需加载远程模块:
const ProductList = lazy(() => importRemote('productApp', './ProductList'));
部署时各子应用独立构建发布到CDN,Host应用更新环境变量即可切换Remote版本,无需重新构建Host。配合版本化CDN路径实现灰度发布:旧版Remote保持可用,新版逐步切换流量。组件库设计中,Module Federation支持跨应用共享UI组件而无需发布npm包,缩短了组件迭代到上线的交付链路。响应式布局的样式和逻辑也可以通过Remote按需加载,避免主应用打包体积膨胀。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/webpack5modulefederation-wei-qian-duan-shi-zhan-yuan-cheng/