使用Webpack模块联邦加载远程React应用时出现TypeError: fn is not a function
问题原因分析
这个fn is not a function错误核心原因有两点:
- 类型不匹配:Angular路由的
loadChildren要求加载的是返回Angular模块工厂的函数,但远程导出的是React组件,并非Angular可识别的模块格式,导致Angular无法解析成可执行的初始化函数,触发错误。 - Remotes配置格式问题:正确的远程模块配置格式应为
[远程应用名称]@[remoteEntry地址],之前加前缀出现解析错误,大概率是远程应用的remoteEntry.js未正确暴露,或是Angular侧的Module Federation配置未正确处理模块解析逻辑。
调试与解决步骤
1. 修正Remotes配置格式
先确保Angular宿主的webpack.config.js中ModuleFederationPlugin的remotes配置正确:
new ModuleFederationPlugin({ name: 'angularHost', remotes: { reactApp: 'reactApp@http://localhost:4203/remoteEntry.js' }, // 其他shared等配置 })
同时验证远程React项目的配置正确性:
// React项目webpack.config.js new ModuleFederationPlugin({ name: 'reactApp', filename: 'remoteEntry.js', exposes: { './ReactApp': './src/App.tsx' }, // shared配置 })
检查http://localhost:4203/remoteEntry.js是否能在浏览器正常访问,确认返回合法JS内容。
2. 改用Angular封装组件加载React应用
loadChildren是专为Angular模块设计的,加载React组件需要通过动态导入+Angular组件封装的方式实现:
步骤1:创建React封装组件
在Angular项目中新建组件,用于渲染React组件:
// react-wrapper.component.ts import { Component, OnInit, ElementRef, OnDestroy } from '@angular/core'; import React from 'react'; import ReactDOM from 'react-dom/client'; import { ReactApp } from 'reactApp/ReactApp'; @Component({ selector: 'app-react-wrapper', template: '<div #reactRoot></div>' }) export class ReactWrapperComponent implements OnInit, OnDestroy { private root: ReactDOM.Root | null = null; constructor(private el: ElementRef) {} ngOnInit(): void { const container = this.el.nativeElement.querySelector('#reactRoot'); this.root = ReactDOM.createRoot(container); this.root.render(React.createElement(ReactApp)); } ngOnDestroy(): void { this.root?.unmount(); } }
步骤2:配置Angular路由
使用loadComponent实现懒加载,替代loadChildren:
// app-routing.module.ts const routes: Routes = [ // 其他路由 { path: 'react-app', loadComponent: () => import('./react-wrapper/react-wrapper.component').then(m => m.ReactWrapperComponent) } ];
步骤3:修正模块声明文件
确保decl.d.ts正确声明远程模块类型:
// decl.d.ts declare module 'reactApp/ReactApp' { import type { ComponentType } from 'react'; const ReactApp: ComponentType; export default ReactApp; }
3. 调试远程模块加载过程
如果问题仍存在,通过以下方式排查:
- 在浏览器开发者工具
Sources面板中,找到remoteEntry.js设置断点,查看远程模块暴露的内容是否符合预期 - 在封装组件中添加日志,确认远程模块导入结果:
// 在react-wrapper.component.ts的ngOnInit中添加 import('reactApp/ReactApp').then(module => { console.log('远程模块内容:', module); // 确认module.default是合法的React组件 });
- 检查shared依赖版本一致性,确保React、ReactDOM等依赖在两个项目中版本匹配,且shared配置正确:
// 两端项目的shared配置示例 shared: { react: { singleton: true, requiredVersion: '^18.2.0' }, 'react-dom': { singleton: true, requiredVersion: '^18.2.0' } }
内容的提问来源于stack exchange,提问作者user842225
相关产品推荐
相关产品推荐

