Angular Module Federation:加载远程MFE时出现NG05100错误
问题现象
单独运行Shell应用与identity微前端(MFE)均正常,但访问MFE路由时触发以下错误:
ERROR Error: Uncaught (in promise): Error: NG05100: Providers from the
BrowserModulehave already been loaded. If you need access to common directives such as NgIf and NgFor, import theCommonModuleinstead.
Error: NG05100: Providers from theBrowserModulehave already been loaded. If you need access to common directives such as NgIf and NgFor, import theCommonModuleinstead.
问题原因
核心问题是identity MFE暴露的是根模块AppModule,而AppModule中导入了BrowserModule。Angular规定BrowserModule只能在整个应用的根模块中加载一次(它包含全局服务提供者),Shell应用作为主应用已经加载过BrowserModule,此时再加载包含BrowserModule的MFE根模块,就会触发重复加载的冲突错误。
解决方案
需要将MFE的业务逻辑拆分到**特性模块(Feature Module)**中,特性模块使用CommonModule替代BrowserModule,同时保留根模块用于MFE单独运行。
步骤1:创建Identity特性模块
在identity项目中新建特性模块,将业务组件、路由等逻辑迁移到该模块:
// projects/identity/src/app/identity/identity.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterModule, Routes } from '@angular/router'; // 导入你的业务组件示例 import { LoginComponent } from './login/login.component'; // MFE内部路由配置 const routes: Routes = [ { path: '', component: LoginComponent }, // 添加其他MFE内部路由 ]; @NgModule({ declarations: [LoginComponent], imports: [ CommonModule, // 使用CommonModule替代BrowserModule RouterModule.forChild(routes) ] }) export class IdentityModule { }
步骤2:修改MFE的Webpack配置
将暴露的模块从根模块AppModule改为新建的Identity特性模块:
// identity的webpack配置文件 const { shareAll, withModuleFederationPlugin, } = require("@angular-architects/module-federation/webpack"); module.exports = withModuleFederationPlugin({ name: "identity", exposes: { "./Module": "./projects/identity/src/app/identity/identity.module.ts", // 指向特性模块 }, shared: { ...shareAll({ singleton: true, strictVersion: true, requiredVersion: "auto", }), }, });
步骤3:调整MFE的根模块AppModule
修改AppModule,使其仅作为MFE单独运行时的根模块,导入BrowserModule和Identity特性模块:
// projects/identity/src/app/app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { RouterModule } from '@angular/router'; import { IdentityModule } from './identity/identity.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, // 仅在根模块加载一次 RouterModule.forRoot([ { path: '', loadChildren: () => import('./identity/identity.module').then(m => m.IdentityModule) } ]), IdentityModule ], bootstrap: [AppComponent] }) export class AppModule { }
步骤4:验证效果
- 单独运行identity MFE:正常启动,根模块加载
BrowserModule无问题 - 运行Shell应用并访问
/identity路由:加载Identity特性模块,该模块使用CommonModule,不会触发重复加载BrowserModule的错误
内容的提问来源于stack exchange,提问作者Atul Verma

