ModuleFederationPlugin报错TypeError: container.init is not a function排查求助
需求场景
MFE1计划通过angular/elements的createCustomElement暴露部分功能及HTML内容;MFE2需直接嵌入并调用该远程MFE的HTML,同时整合多个领域特定MFE。
现有配置代码
MFE1的Webpack配置
const singleSpaAngularWebpack = require('single-spa-angular/lib/webpack').default; const { merge } = require('webpack-merge'); const { EnvironmentPlugin } = require('webpack'); const { ModuleFederationPlugin } = require('webpack').container; require('dotenv').config(); module.exports = (config, options) => { const singleSpaWebpackConfig = singleSpaAngularWebpack(config, options); return merge(singleSpaWebpackConfig, { output: { scriptType: 'text/javascript' }, plugins: [new ModuleFederationPlugin({ name: 'mfe1', filename: 'remoteEntry.js', exposes: { './Module': 'src/app/app.module.ts', } }), new EnvironmentPlugin(['ENVIRONMENT'])], }) }
MFE2的main.ts文件
import { loadRemoteEntry } from '@angular-architects/module-federation'; Promise.all([ loadRemoteEntry({ type: 'module', remoteEntry: 'http://localhost:4206/remoteEntry.js', }), ]) .catch((err) => console.error('Error loading remote entries', err)) .then(() => import('./bootstrap')) .catch((err) => console.error(err));
MFE2的路由文件
import { APP_BASE_HREF } from '@angular/common'; import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AppComponent } from './app.component'; import { EmptyRouteComponent } from './core/components/empty-route/empty-route.component'; import { loadRemoteModule } from '@angular-architects/module-federation'; const routes: Routes = [ { path: 'test', loadChildren: () => loadRemoteModule({ type: 'module', remoteEntry: 'http://localhost:4206/remoteEntry.js', exposedModule: './Module' }) .then(m => m.MyModule) }, { path: '**', component: EmptyRouteComponent }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], providers: [{ provide: APP_BASE_HREF, useValue: '/' }], }) export class AppRoutingModule {}
错误现象
ngx-logger.mjs:607 2023-02-19T14:59:44.358Z ERROR [main.js:575:21] Error from global error handler in order Error: Uncaught (in promise): TypeError: container.init is not a function TypeError: container.init is not a function at angular-architects-module-federation-runtime.mjs:27:1 ngx-logger.mjs:607 2023-02-19T14:59:44.363Z ERROR [main.js:575:21] Error from global error handler in order Error: Uncaught (in promise): TypeError: container.get is not a function TypeError: container.get is not a function at angular-architects-module-federation-runtime.mjs:10:1
问题根源及修复方案
核心问题
你同时混用了single-spa-angular的Webpack配置和Module Federation插件,两者的容器规范完全冲突:single-spa会生成自有容器逻辑,覆盖或干扰Module Federation的容器体系,导致angular-architects的运行时找不到正确的init/get方法。此外,当前配置也没有配合Angular Elements的暴露逻辑。
修复步骤
移除single-spa-angular依赖
删除MFE1 Webpack配置中所有single-spa相关代码,改用标准Angular+Module Federation配置,因为你不需要single-spa实现Elements暴露:const { merge } = require('webpack-merge'); const { EnvironmentPlugin } = require('webpack'); const { ModuleFederationPlugin } = require('webpack').container; const { AngularWebpackPlugin } = require('@ngtools/webpack'); require('dotenv').config(); module.exports = (config, options) => { return merge(config, { output: { scriptType: 'text/javascript' }, plugins: [ new ModuleFederationPlugin({ name: 'mfe1', filename: 'remoteEntry.js', exposes: { './MyElement': 'src/app/my-element/my-element.component.ts', // 直接暴露要转为Custom Element的组件 } }), new EnvironmentPlugin(['ENVIRONMENT']), new AngularWebpackPlugin({ tsConfig: './tsconfig.json', entryModule: './src/app/app.module.ts#AppModule' }) ], }) }在MFE1中实现Angular Elements导出
在MFE1的app.module.ts中注册Custom Element,并确保Module Federation能正确导出:import { NgModule, Injector } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { createCustomElement } from '@angular/elements'; import { MyElementComponent } from './my-element/my-element.component'; @NgModule({ imports: [BrowserModule], declarations: [MyElementComponent], entryComponents: [MyElementComponent] }) export class AppModule { constructor(private injector: Injector) {} ngDoBootstrap() { const el = createCustomElement(MyElementComponent, { injector: this.injector }); customElements.define('my-element', el); } } // 导出供Module Federation调用 export const MyElement = MyElementComponent;调整MFE2的调用逻辑
MFE2不需要通过路由懒加载模块,直接加载远程Custom Element定义后,在模板中使用自定义标签:- 修改MFE2的
main.ts:import { loadRemoteModule } from '@angular-architects/module-federation'; Promise.all([ loadRemoteModule({ type: 'module', remoteEntry: 'http://localhost:4206/remoteEntry.js', exposedModule: './MyElement' }) ]) .catch((err) => console.error('Error loading remote elements', err)) .then(() => import('./bootstrap')) .catch((err) => console.error(err)); - 在MFE2的组件模板中直接使用:
<my-element></my-element>
- 修改MFE2的
统一依赖版本
确认@angular-architects/module-federation、@angular/elements与Angular核心版本完全匹配,避免版本不兼容引发的运行时错误。
内容的提问来源于stack exchange,提问作者naveen

