2024-03-31 08:23:55
Webpack 5 的模块联邦(Module Federation)通过构建时配置与运行时动态加载结合的方式,实现 JavaScript 代码的跨应用共享。其核心机制围绕 expose、remotes 和 shared 三个关键配置项展开,具体实现流程如下:
1. Remote 应用暴露模块远程应用(提供共享代码的一方)需通过 ModuleFederationPlugin 显式声明对外暴露的模块,并生成入口文件(如 remoteEntry.js)。
关键配置项:
name:远程应用的唯一标识,供其他应用引用。
exposes:以键值对形式声明暴露的模块路径,键为模块别名,值为实际文件路径。
shared:定义共享的第三方依赖(如 React、Lodash),避免重复加载。
示例配置:
new ModuleFederationPlugin({ name: 'remoteApp', filename: 'remoteEntry.js', // 生成的入口文件名 exposes: { './Button': './src/components/Button', // 暴露组件 './utils': './src/utils/common' // 暴露工具函数 }, shared: { react: { singleton: true }, // 强制单例,避免冲突 'react-dom': { singleton: true } }});输出结果:
生成 remoteEntry.js 文件,包含模块清单和加载逻辑。
暴露的模块可通过别名(如 ./Button)被其他应用引用。
主应用(消费共享代码的一方)需配置远程应用的加载地址,并通过动态 import() 按需加载模块。
关键配置项:
remotes:声明远程应用的名称与加载地址,格式为 远程应用名: '远程应用名@加载地址'。
shared:与远程应用共享相同的依赖配置,确保版本一致。
示例配置:
new ModuleFederationPlugin({ name: 'hostApp', remotes: { remoteApp: 'remoteApp@动态加载模块:使用 import() 语法实现懒加载,返回 Promise 对象:
const Button = await import('remoteApp/Button'); // 加载远程组件const utils = await import('remoteApp/utils'); // 加载远程工具函数通过 shared 配置,多个应用可共用同一版本的第三方库,减少重复加载,提升性能。
核心机制:
singleton: true:确保依赖全局唯一,避免版本冲突。
运行时协商:Webpack 会优先使用已加载的依赖版本,若版本不兼容则抛出错误。
示例配置:
shared: { react: { singleton: true, requiredVersion: '^17.0.0' // 可选:指定版本范围 }, lodash: { singleton: true }}当 Host 应用请求远程模块时,Webpack 执行以下步骤:
Host 应用首先下载远程应用的 remoteEntry.js 文件,获取模块清单。
Webpack 的容器机制解析模块别名(如 remoteApp/Button),定位到实际文件。
调用 import() 时,动态下载对应的代码块(Chunk)并执行。
远程模块在 Host 应用中以 ES Module 形式返回,可直接使用。
Webpack 5 的模块联邦通过暴露模块、动态加载和依赖共享三大机制,实现了跨应用的代码复用。其核心优势在于:
正确配置 expose、remotes 和 shared 是关键,同时需关注版本兼容性与单例管理。