如何通过Module Federation在同域主应用与IFrame间共享React依赖?
同域主应用与IFrame共享React等依赖的实现方案
一、原生全局挂载方案(无需Module Federation)
直接通过window全局对象共享库实例,简单易落地:
- 主应用侧操作:在主应用入口文件中,将需要共享的库挂载到全局
window:
import React from 'react'; import ReactDOM from 'react-dom/client'; // 挂载全局共享对象,命名需唯一避免冲突 window.SharedReact = React; window.SharedReactDOM = ReactDOM;
- IFrame侧配置:在IFrame的Webpack配置中,用
externals声明依赖从全局获取,避免重复打包:
// IFrame的webpack.config.js module.exports = { // 其他配置... externals: { react: 'SharedReact', 'react-dom': 'SharedReactDOM' } };
此时IFrame打包时不会将React/ReactDOM打入bundle,运行时直接引用主应用挂载的全局实例,实现依赖共享。
二、适配Module Federation的跨IFrame共享方案
你提到的Module Federation作者所说的“全局对象”,指的是主应用暴露到全局的Webpack模块容器。通过让IFrame访问该容器,即可实现跨上下文的依赖共享:
- 主应用侧配置:
常规配置Module Federation共享规则,同时将模块容器挂载到全局:
// 主应用webpack.config.js const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); module.exports = { // 其他配置... plugins: [ new ModuleFederationPlugin({ name: 'hostApp', shared: { react: { singleton: true, eager: true }, 'react-dom': { singleton: true, eager: true } } }) ] }; // 主应用入口文件(bootstrap前) window.hostContainer = __webpack_container__; // 暴露主应用模块容器到全局 import('./bootstrap');
- IFrame侧配置:
配置Module Federation时禁止本地加载共享依赖,然后从主应用的全局容器获取实例:
// IFrame的webpack.config.js const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); module.exports = { // 其他配置... plugins: [ new ModuleFederationPlugin({ name: 'iframeApp', shared: { react: { singleton: true, eager: true, import: false, // 禁止从IFrame本地加载 requiredVersion: '^18.0.0' // 需与主应用版本一致 }, 'react-dom': { singleton: true, eager: true, import: false, requiredVersion: '^18.0.0' } } }) ] }; // IFrame入口文件 import { initSharing } from '@module-federation/runtime'; async function initSharedDependencies() { // 初始化共享范围 await initSharing('default'); // 从主应用全局容器获取共享模块 const reactModule = await window.parent.hostContainer.get('./react'); const reactDomModule = await window.parent.hostContainer.get('./react-dom'); // 将获取到的模块挂载到IFrame全局,供内部使用 window.SharedReact = reactModule.default; window.SharedReactDOM = reactDomModule.default; // 加载IFrame业务代码 import('./bootstrap'); } // 确保主应用容器已挂载后再初始化 if (window.parent.hostContainer) { initSharedDependencies(); } else { // 监听主应用容器挂载事件(可选) window.parent.addEventListener('containerReady', initSharedDependencies); }
关键注意事项
- 主应用与IFrame的依赖版本必须完全匹配,否则会引发实例不兼容问题;
- 全局变量命名需唯一,避免与其他脚本冲突;
- 使用Module Federation时,
eager: true确保共享模块在入口阶段加载,保证IFrame能获取到实例; - 若使用React 18+,需注意
ReactDOM.createRoot的调用方式与全局实例的兼容性。
内容的提问来源于stack exchange,提问作者Diogo Soares
相关产品推荐
相关产品推荐

