Webpack Module Federation插件:Angular宿主无法渲染React远程微前端
微前端React远程应用无法渲染问题排查思路
问题背景
使用Webpack的ModuleFederationPlugin构建微前端系统,包含1个Angular宿主应用、1个Angular远程应用、1个React远程应用。Angular宿主可正常渲染Angular远程应用,但React远程应用无法显示,具体现象:
- 页面已生成
<react-element></react-element>标签,但内容为空 - 导航至
/reactMFE路径时,浏览器Source标签可见React应用的remoteEntry.js及其他文件已下载 - React应用单独启动可正常运行
相关配置
Angular宿主应用路由配置
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import {HomeComponent} from './core/home/home.component'; import {WebComponentWrapper, WebComponentWrapperOptions} from '@angular-architects/module-federation-tools'; const routes: Routes = [ { path: '', component: HomeComponent, pathMatch: 'full' }, { path: 'ngMFE', loadChildren: () => import('mf1/Module').then(m => m.HeroesModule) }, { path: 'reactMFE', component: WebComponentWrapper, data: { type: 'script', remoteEntry: 'http://localhost:3000/remoteEntry.js', remoteName: 'mf2', exposedModule: './AppModule', elementName: 'react-element', } as WebComponentWrapperOptions, } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
React应用Webpack配置
const HtmlWebpackPlugin = require('html-webpack-plugin'); const path = require('path'); const { ModuleFederationPlugin } = require('webpack').container; const deps = require('./package.json').dependencies; module.exports = (env, argv) => { const mode = 'development'; console.log({ mode }); return { performance: { hints: false }, entry: `./src/index.ts`, output: { path: path.resolve(__dirname, 'dist'), filename: 'mf2/mf2Module.js' }, devServer: { port: 3000, open: false, }, devtool: 'inline-source-map', mode, resolve: { extensions: ['.ts', '.tsx', '.js'], }, module: { rules: [ { test: /\.(js|jsx|tsx|ts)$/, loader: 'ts-loader', exclude: /node_modules/, } ], }, plugins: [ new ModuleFederationPlugin({ name: 'mf2', filename: 'remoteEntry.js', exposes: { './AppModule': './src/App', }, shared: { ...deps, react: { singleton: true, eager: true, requiredVersion: deps.react }, 'react-dom': { singleton: true, eager: true, requiredVersion: deps["react-dom"], }, }, }), new HtmlWebpackPlugin({ template: `./public/index.html`, }), ] }; };
解决思路
1. 确保React组件已封装为Web Component
Angular的WebComponentWrapper仅支持渲染标准Web Component,普通React组件无法直接被识别。需将React组件转换为自定义元素:
- 安装转换工具:
npm install @r2wc/react-to-web-component - 修改
src/App.tsx,封装并注册自定义元素:
import React from 'react'; import r2wc from '@r2wc/react-to-web-component'; const App = () => { return <div>React MFE Content</div>; }; // 将React组件转为Web Component,若有props可在此定义类型 const ReactElement = r2wc(App, {}); // 注册自定义元素,名称需与宿主配置的elementName完全一致 customElements.define('react-element', ReactElement); export default App;
2. 调整React应用入口逻辑
单独运行时的渲染逻辑会与微前端模式冲突,需区分环境加载不同逻辑:
- 创建
src/bootstrap.tsx,存放单独运行时的渲染代码:
import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')!); root.render( <React.StrictMode> <App /> </React.StrictMode> );
- 修改
src/index.ts,根据环境判断加载逻辑:
// 判断是否作为微前端远程模块加载 if (!window['__webpack_init_sharing__']) { // 单独运行时执行渲染逻辑 import('./bootstrap'); } else { // 作为远程模块时,仅注册Web Component,由宿主负责渲染 import('./App'); }
3. 检查共享依赖一致性
确保Angular宿主与React远程应用的React、ReactDOM版本完全一致,且宿主也配置了对应共享依赖(若未配置,需在宿主的ModuleFederationPlugin中添加):
// 宿主应用ModuleFederation配置示例 shared: { react: { singleton: true, eager: true, requiredVersion: 'x.x.x' }, 'react-dom': { singleton: true, eager: true, requiredVersion: 'x.x.x' }, }
4. 排查浏览器控制台错误
打开浏览器开发者工具Console标签,重点查看以下类型错误:
- 自定义元素未定义(
Uncaught ReferenceError: CustomElement is not defined) - React初始化失败(如版本冲突、重复加载)
- DOM节点找不到(
Target container is not a DOM element)
5. 确认远程模块导出路径
检查React应用ModuleFederationPlugin的exposes配置,确保./AppModule指向的文件确实导出了已封装的Web Component,且与宿主路由配置的exposedModule完全匹配。
内容的提问来源于stack exchange,提问作者Cyberpunker
相关产品推荐
相关产品推荐

