Angular模块联邦中如何向壳应用全局提供远程注入令牌?
在Angular Module Federation中让远程注入令牌全局生效的方案
完全可行,你遇到的问题核心在于:远程模块默认会将自身的providers注册到模块级注入器,而非壳应用的根注入器;而provideIn: root的服务是在根注入器中创建的,自然无法获取到远程模块作用域内的令牌。下面是几种无需手动在远程主模块声明所有服务的解决方案:
方案1:加载远程模块后手动注册令牌到根注入器
在远程模块中导出令牌的提供者集合,壳应用加载远程模块后,将这些提供者注册到根环境注入器中,让所有根级服务都能访问到。
远程模块代码:
// remote/src/app/remote.module.ts import { InjectionToken, Provider } from '@angular/core'; // 定义注入令牌 export const MY_REMOTE_TOKEN = new InjectionToken<string>('MY_REMOTE_TOKEN'); // 导出令牌提供者集合 export const REMOTE_TOKEN_PROVIDERS: Provider[] = [ { provide: MY_REMOTE_TOKEN, useValue: '来自远程模块的全局令牌值' }, // 可添加其他需要全局生效的令牌 ]; @NgModule({ // 无需在当前模块的providers中声明这些令牌 declarations: [...], imports: [...] }) export class RemoteModule {}
壳应用代码:
在壳应用的初始化逻辑中(比如通过APP_INITIALIZER确保在根服务启动前完成注册),加载远程模块并注册令牌:
// shell/src/app/app.module.ts import { NgModule, APP_INITIALIZER, inject, EnvironmentInjector } from '@angular/core'; import { LoadRemoteModule } from '@angular-architects/module-federation'; // 加载远程模块并注册令牌的函数 async function registerRemoteTokens(): Promise<void> { const remoteModule = await LoadRemoteModule({ type: 'module', remoteEntry: 'http://localhost:3000/remoteEntry.js', exposedModule: './Module' }); // 获取远程模块导出的令牌提供者 const remoteProviders = remoteModule.REMOTE_TOKEN_PROVIDERS; // 注册到根环境注入器 const rootInjector = inject(EnvironmentInjector); remoteProviders.forEach(provider => rootInjector.registerProvider(provider)); } @NgModule({ providers: [ { provide: APP_INITIALIZER, useFactory: () => registerRemoteTokens, multi: true, deps: [] } ], declarations: [...], imports: [...] }) export class AppModule {}
方案2:远程模块初始化时自动注册令牌到根注入器
让远程模块在加载完成后,自动将令牌注册到根注入器,无需壳应用额外处理。
远程模块代码:
// remote/src/app/remote.module.ts import { NgModule, inject, EnvironmentInjector } from '@angular/core'; import { MY_REMOTE_TOKEN } from './tokens'; @NgModule({ declarations: [...], imports: [...] }) export class RemoteModule { constructor() { // 获取根环境注入器并注册令牌 const rootInjector = inject(EnvironmentInjector); rootInjector.registerProvider({ provide: MY_REMOTE_TOKEN, useValue: '来自远程模块的全局令牌值' }); } }
这种方式下,只要远程模块被加载,其构造函数就会自动将令牌注册到根注入器,壳应用的根级服务(包括provideIn: root的服务)就能直接注入使用。
注意事项
- 确保壳应用与远程模块使用的Angular版本兼容,避免因注入器API差异导致的问题(
EnvironmentInjector.registerProvider从Angular 14开始支持)。 - 如果多个远程模块注册了相同的注入令牌,后加载的模块会覆盖之前的令牌值,需注意业务逻辑中的优先级。
- 使用
APP_INITIALIZER能确保令牌在根服务初始化前完成注册,避免出现No provider for XXX的错误。
内容的提问来源于stack exchange,提问作者Rafał Gąsior
相关产品推荐
相关产品推荐

