JavaScript中的模块联邦是webpack5引入的重要特性,它允许不同构建产物之间直接共享模块,不需要把依赖重复打包到各自的bundle中,在微前端、多应用协同等场景中应用十分广泛。它的核心目标是解决多应用之间的模块复用和依赖管理问题,让跨应用的代码共享变得更灵活高效。

模块联邦的核心概念
要理解模块联邦的原理,首先需要明确几个核心角色:
- 宿主应用(Host):主动加载其他应用模块的应用,也就是消费者角色,会在运行时请求远程应用的模块资源。
- 远程应用(Remote):对外暴露模块供其他应用使用的应用,也就是提供者角色,会把自身需要共享的模块打包成独立的远程入口文件。
- 共享依赖(Shared):多个应用共同依赖的第三方库或者公共模块,模块联邦可以约定共享版本,避免重复加载。
- 远程入口(Remote Entry):远程应用生成的特殊文件,里面包含了远程应用暴露的所有模块的信息和加载逻辑,宿主应用通过加载这个文件来获取远程模块的访问能力。
模块联邦的构建时原理
在构建阶段,webpack会根据模块联邦的配置做特殊的处理,主要分为远程应用和宿主应用两部分:
远程应用的构建处理
远程应用需要在webpack配置中通过ModuleFederationPlugin声明要暴露的模块和共享依赖,配置示例如下:
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
module.exports = {
plugins: [
new ModuleFederationPlugin({
// 远程应用的名称,其他应用通过这个名称来引用当前应用的模块
name: 'remote_app',
// 远程入口文件的名称,默认是remoteEntry.js
filename: 'remoteEntry.js',
// 暴露给外部的模块,键是外部引用的路径,值是本地模块的路径
exposes: {
'./Button': './src/components/Button.jsx',
'./utils': './src/utils/index.js'
},
// 共享的依赖,这里声明react和react-dom为共享依赖
shared: {
react: { singleton: true },
'react-dom': { singleton: true }
}
})
]
};
构建时webpack会为远程应用生成两个关键部分:
- 独立的远程入口文件(remoteEntry.js),这个文件不包含具体模块的代码,只包含模块的元信息、加载函数和共享依赖的版本校验逻辑。
- 暴露的模块会被打包成独立的chunk文件,只有当宿主应用真正请求对应模块的时候才会被加载。
宿主应用的构建处理
宿主应用同样需要配置ModuleFederationPlugin,声明要加载的远程应用和共享依赖:
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
module.exports = {
plugins: [
new ModuleFederationPlugin({
// 宿主应用的名称
name: 'host_app',
// 声明远程应用的引用,键是远程应用的别名,值是远程入口文件的地址
remotes: {
remote_app: 'remote_app@http://localhost:3001/remoteEntry.js'
},
// 共享的依赖,需要和远程应用的共享依赖配置匹配
shared: {
react: { singleton: true },
'react-dom': { singleton: true }
}
})
]
};
构建时webpack会在宿主应用的bundle中注入远程模块的加载逻辑,把对远程模块的引用替换成异步加载的函数,不会把远程模块的代码打包到宿主应用的bundle中。
模块联邦的运行时原理
构建完成后,模块联邦的核心工作流程在运行时展开,主要分为几个步骤:
1. 加载远程入口文件
当宿主应用执行到引用远程模块的代码时,比如下面的代码:
// 动态导入远程应用的Button组件
const RemoteButton = React.lazy(() => import('remote_app/Button'));
webpack注入的加载逻辑会先检查远程应用remote_app的远程入口文件是否已经加载,如果没有加载,就会发起网络请求获取http://localhost:3001/remoteEntry.js,这个文件执行后会在全局注册一个和远程应用名称对应的容器对象,里面包含了该远程应用所有暴露模块的信息。
2. 模块加载与依赖解析
远程入口文件加载完成后,宿主应用会调用容器对象上的模块获取方法,这时候会触发远程模块对应chunk的加载。如果远程模块依赖了共享依赖,会先检查当前宿主应用中是否已经加载了符合版本要求的共享依赖:
- 如果已经加载,就直接使用宿主应用的共享依赖,不会重复加载。
- 如果没有加载或者版本不匹配,才会加载远程应用自带的对应依赖。
这里的singleton: true配置就是保证共享依赖只会加载一个实例,避免多实例导致的状态冲突问题。
3. 模块缓存与复用
模块联邦会在内部维护一个模块缓存池,所有加载过的远程模块和共享依赖都会被缓存起来。如果后续其他地方的代码再次引用同一个远程模块,会直接从缓存中读取,不需要再次发起网络请求,提升了再次访问的性能。
核心原理总结
模块联邦的本质是在构建时拆分模块的职责,把模块的元信息和实际代码分离,运行时通过动态加载的方式按需获取远程模块,同时通过共享依赖的机制避免重复打包和加载。它打破了传统模块打包的边界,让不同构建产物之间的模块可以直接通信和复用,这也是它能在微前端场景中快速流行起来的核心原因。
需要注意的是,模块联邦目前主要是webpack生态的特性,其他构建工具如vite也有类似的实现,但核心原理都是基于运行时的动态模块加载和共享逻辑。
Module_FederationJavaScriptwebpack微前端模块共享修改时间:2026-06-11 18:09:36