Angular Module Federation问题:远程模块forRoot未调用致配置缺失
问题分析与解决方案
这个问题核心在于Module Federation的共享模块单例机制:你用shareAll把所有依赖都设为单例共享(singleton: true),当Shell应用和远程MFE都依赖SomeApiModule时,Shell会优先创建该模块的单例实例,远程MFE里SomeApiModule.forRoot(...)的配置代码根本不会执行——因为模块已经被初始化过了。
解决方案1:取消共享SomeApiModule
如果SomeApiModule不需要跨应用共享实例,直接在远程应用的webpack配置里排除它,让远程模块自己初始化带配置的实例:
修改远程应用webpack.config.ts:
const { shareAll, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack'); module.exports = withModuleFederationPlugin({ name: 'mfe', exposes: { './Module': './projects/mfe1/src/app/feature/feature.module.ts', }, shared: { ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }), // 排除SomeApiModule,不让它被共享 '@generated/some-api': false }, });
解决方案2:共享时统一配置(适合需要单例的场景)
如果必须共享SomeApiModule的单例,需要在Shell应用里统一配置,或者让远程模块通过其他方式注入配置:
方式A:Shell中全局配置forRoot
在Shell的AppModule里导入SomeApiModule.forRoot(...),这样远程MFE会复用这个已配置好的实例:
// Shell的app.module.ts import { SomeApiModule } from '@generated/some-api'; @NgModule({ imports: [ ..., SomeApiModule.forRoot(() => new Configuration({basePath: "foo"})), RouterModule.forRoot([/* 路由配置 */]) ] }) export class AppModule { }
方式B:远程模块用依赖注入传递配置
如果需要远程模块自己控制配置,可改用InjectionToken传递配置,避免依赖forRoot的单次执行:
- 在远程模块中定义配置Token:
// feature.module.ts import { InjectionToken, ModuleWithProviders, NgModule } from '@angular/core'; import { SomeApiModule, Configuration } from '@generated/some-api'; export const API_CONFIG = new InjectionToken<Configuration>('API_CONFIG'); @NgModule({ declarations: [FeatureComponent], imports: [ ..., RouterModule.forChild(FEATUE_ROUTES), SomeApiModule ], exports: [FeatureComponent] }) export class FeatureModule { static forRoot(config: Configuration): ModuleWithProviders<FeatureModule> { return { ngModule: FeatureModule, providers: [ { provide: API_CONFIG, useValue: config }, { provide: Configuration, useFactory: (config) => config, deps: [API_CONFIG] } ] }; } }
- Shell加载远程模块时调用
forRoot:
// Shell的app.module.ts路由配置 { path: 'feature', loadChildren: () => loadRemoteModule({ type: 'manifest', remoteName: 'mfe', exposedModule: './Module' }) .then(m => m.FeatureModule.forRoot(new Configuration({basePath: "foo"}))), }
验证
修改后重启Shell和远程应用,切换到feature路由时,检查控制台是否输出in forRoot(对应方案1),或者确认API请求的basePath是否正确配置。
内容的提问来源于stack exchange,提问作者feodorar
相关产品推荐
相关产品推荐

