Angular Webpack Module Federation场景下InjectionToken注入报错求解
问题产生原因
- 最核心的原因是公共库多副本导致InjectionToken实例不唯一:微前端架构下如果没有将
EclatechCore公共库配置为全局单例共享,Shell主应用和mfe1子应用会各自打包一份公共库代码,两份代码里导出的ENVIRONMENTInjectionToken是完全不同的引用实例,Angular依赖注入是按实例匹配而不是按Token的字符串名称匹配,因此mfe1中给自有副本的Token提供的配置值,无法被另一份副本的依赖消费方识别。 - 次要原因是注入器层级不匹配:如果你在公共库中定义的
ConfigService、BusinessService使用了providedIn: 'root'声明为根注入器单例,而你将EclatechCoreModule.forRoot(config)写在子业务模块SetupModule中,那么ENVIRONMENT的提供者只会注册在SetupModule的子注入器中,根注入器中没有对应提供者,根注入器实例化的Service自然找不到依赖。独立启动mfe1时正常是因为此时SetupModule的注入器层级更接近根,或者独立启动时不会触发跨应用的注入器隔离逻辑。
解决方案
- 配置公共库为全局单例
如果你使用的是Module Federation作为微前端实现,在Shell和所有子应用的微前端配置中,将EclatechCore公共库加入共享依赖列表,设置单例属性:
// webpack.config.js 或 module-federation.config.js 中的shared配置 shared: { "@your-scope/eclatech-core": { // 替换为你的公共库的包名或路径别名 singleton: true, strictVersion: false, // 如果版本能保证一致可以设为true requiredVersion: "auto" }, // 其他共享依赖比如@angular/core之类的也建议按同样规则配置单例 }
该配置可以保证整个微前端环境中只有一份公共库代码,所有应用共用同一个ENVIRONMENT Token实例,从根源解决实例不匹配问题。
调整forRoot调用位置
将mfe1中EclatechCoreModule.forRoot(config)的调用从业务子模块SetupModule迁移到mfe1的**根模块(AppModule)**的imports数组中,保证ENVIRONMENT的提供者注册在mfe1的根注入器中,不管是独立启动还是被Shell加载,都能被根注入器下的所有Service访问到。修复Service的注入范围
如果公共库中的业务Service使用了providedIn: 'root'声明,修改为providedIn: EclatechCoreModule,让Service和它依赖的ENVIRONMENT属于同一个模块的注入器范围,避免跨注入器查找依赖失败。临时兼容方案
如果暂时无法调整公共库的共享配置,可以在mfe1的SetupModule的providers数组中直接声明ENVIRONMENT的提供者,不需要依赖公共模块的forRoot返回:
@NgModule({ declarations: [SetupComponent], imports: [ CommonModule, RouterModule.forChild([ { path: '', component: SetupComponent, } ]), EclatechCoreModule // 不需要在这里调用forRoot ], providers: [ { provide: ENVIRONMENT, useValue: config } ], exports:[ SetupComponent ] }) export class SetupModule { }
注意该方案需要保证mfe1中导入的ENVIRONMENT和业务Service依赖的ENVIRONMENT是同一个引用,仅适合临时排查问题使用,不推荐长期使用。
内容的提问来源于stack exchange,提问作者Hary
相关产品推荐
相关产品推荐

