JavaScript模块联邦是Webpack5引入的分布式模块共享方案,它允许不同构建产物在运行时互相加载对方的模块,无需将依赖提前打包到自身产物中,完美解决了跨应用组件共享时的依赖冗余、版本同步等问题,是微前端架构下组件复用的重要技术方案。
模块联邦核心概念
模块联邦的运行依赖几个核心角色,理解这些概念是配置和使用的基础:
- Host(宿主应用):负责加载远程模块的应用,也就是消费共享组件的一方
- Remote(远程应用):暴露自身模块供其他应用加载的应用,也就是提供共享组件的一方
- shared:配置需要共享的依赖,避免重复加载相同版本的依赖包
- exposes:远程应用中配置需要暴露给外部访问的模块路径
- remotes:宿主应用中配置需要加载的远程应用地址和模块别名
基础配置示例
下面通过两个独立应用演示跨应用组件共享的完整流程,首先创建远程应用,暴露一个通用按钮组件。
远程应用配置(提供组件方)
远程应用的Webpack配置中添加模块联邦插件:
// webpack.config.js
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: 'http://localhost:3001/'
},
devServer: {
port: 3001,
publicPath: 'http://localhost:3001/'
},
plugins: [
new ModuleFederationPlugin({
// 远程应用唯一名称,其他应用通过该名称引用
name: 'remoteApp',
// 远程应用的入口文件,暴露的模块会挂载到这个文件下
filename: 'remoteEntry.js',
// 暴露给外部的模块
exposes: {
'./Button': './src/components/Button.jsx'
},
// 共享的依赖,指定版本范围避免重复加载
shared: {
react: { singleton: true, requiredVersion: '^18.0.0' },
'react-dom': { singleton: true, requiredVersion: '^18.0.0' }
}
})
]
};
远程应用暴露的按钮组件代码如下:
// src/components/Button.jsx
import React from 'react';
const Button = (props) => {
return (
<button style={{ padding: '8px 16px', backgroundColor: '#1890ff', color: '#fff', border: 'none', borderRadius: '4px' }} {...props}>
{props.children || '共享按钮'}
</button>
);
};
export default Button;
宿主应用配置(消费组件方)
宿主应用同样需要配置模块联邦插件,声明要加载的远程应用:
// webpack.config.js
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: 'http://localhost:3000/'
},
devServer: {
port: 3000,
publicPath: 'http://localhost:3000/'
},
plugins: [
new ModuleFederationPlugin({
name: 'hostApp',
// 声明远程应用,别名: 远程应用入口地址
remotes: {
remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js'
},
// 共享的依赖需要和远程应用保持一致
shared: {
react: { singleton: true, requiredVersion: '^18.0.0' },
'react-dom': { singleton: true, requiredVersion: '^18.0.0' }
}
})
]
};
宿主应用中加载并使用远程按钮组件:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
// 动态加载远程模块
const RemoteButton = React.lazy(() => import('remoteApp/Button'));
const App = () => {
return (
<div style={{ padding: '20px' }}>
<h2>宿主应用</h2>
<p>下面是来自远程应用的共享按钮组件:</p>
<React.Suspense fallback={<div>加载中...</div>}>
<RemoteButton onClick={() => alert('点击了共享按钮')} />
</React.Suspense>
</div>
);
};
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
关键配置说明
实际使用中需要注意几个核心配置的细节:
- singleton配置:设置为true时,共享依赖只会加载一个实例,避免多版本React导致的上下文报错问题
- requiredVersion:指定依赖的版本范围,只有版本匹配时才会共享依赖,避免版本不兼容问题
- remoteEntry.js:是远程应用的模块清单文件,宿主应用通过该文件获取远程模块的加载地址和依赖信息
- 动态加载:远程模块加载是异步的,需要配合
React.lazy或者import()语法实现按需加载
使用注意事项
模块联邦虽然简化了跨应用组件共享流程,但使用时也有一些需要注意的点:
远程应用和宿主应用的共享依赖版本需要尽量保持一致,否则可能出现依赖不共享、重复加载的情况,甚至引发运行时错误。
另外,远程应用的地址需要保证宿主应用可以访问,生产环境需要配置正确的publicPath,避免资源加载404。如果多个应用共享同一个组件,只需要更新远程应用的组件代码,所有宿主应用刷新后就能获取最新版本,不需要重新打包宿主应用,大幅提升了迭代效率。
适用场景
模块联邦非常适合以下场景:
- 微前端架构下多个子应用共享通用组件、工具函数
- 大型单体应用拆分后,拆分出的模块需要互相复用代码
- 多个独立项目需要共用同一套UI组件库,且需要实时同步更新
相比传统的npm包共享方案,模块联邦不需要频繁发布更新包、重新安装依赖,运行时动态加载的特性让跨应用组件共享更加灵活高效。
JavaScript模块联邦跨应用组件共享Webpack微前端修改时间:2026-06-24 01:06:58