动态创建的模块和组件无权访问父注入器

Bra*_*rLC 5 dependency-injection microservices angular micro-frontend

我们目前有一个问题,我们想动态创建一个模块(moduleFactory.create(this.injector))。但是动态创建的模块的注入器没有来自父注入器的提供者。我们希望在我们的集成/主应用程序(创建子模块的地方)中实现一些核心内容,将其放入根注入器,并希望通过 DI(通过注入器,由主注入器创建)将其放入我们的子模块和组件中应用程序的注入器作为父级)。

我们的实现基于这个例子:https : //stackblitz.com/edit/angular-ifs7sp?file=src%2Fapp%2Flazy-loader.service.ts

const subsystems = await this.fetchSubsystems()

const promises = subsystems
  .map(async (subsystem) => await subsystem.load())

const subsystemModuleFactories = await Promise.all(promisses)

subsystemModuleFactories.map(async (ngModuleOrNgModuleFactory) => {
  let moduleFactory: NgModuleFactory<any>
  if (ngModuleOrNgModuleFactory instanceof NgModuleFactory) {
    moduleFactory = ngModuleOrNgModuleFactory
  } else {
    const compiler = this.injector.get(Compiler)
    moduleFactory = await compiler.compileModuleAsync(ngModuleOrNgModuleFactory)
  }

  const entryComponent = (<any>moduleFactory.moduleType).entry
  const moduleRef = moduleFactory.create(this.injector) // create the module ref with the injector of the main app as parent of the subsystem module
  // Here we can still get the instance console.log(moduleRef.injector.get(I18n))
  const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent)

  container.createComponent(compFactory)
})
Run Code Online (Sandbox Code Playgroud)

fetchSubsystems在短期使用SystemJS导入单个包文件,并返回出口的AppModule:

SystemJS.import('subsystem') // mapped to an actual URL
    .then((m) => (m as any).AppModule)
Run Code Online (Sandbox Code Playgroud)

在子系统中,我们要使用该服务:

export class AppComponent {
  public constructor (@Inject(I18n) private i18n: II18n) {
  }
}
Run Code Online (Sandbox Code Playgroud)

I18nInjectionTokenII18n定义了服务的接口:

import { InjectionToken } from '@angular/core'

export interface II18n {
  tr(key: string): string
}

export const I18n = new InjectionToken<II18n>('I18n')
Run Code Online (Sandbox Code Playgroud)

不幸的是,我们得到了一个错误,在注入器中没有这样的 InjectionToken:

ERROR Error: Uncaught (in promise): NullInjectorError: StaticInjectorError(AppModule)[AppComponent -> InjectionToken I18n]: 
  StaticInjectorError(Platform: core)[AppComponent -> InjectionToken I18n]: 
    NullInjectorError: No provider for InjectionToken I18n!
NullInjectorError: StaticInjectorError(AppModule)[AppComponent -> InjectionToken I18n]: 
  StaticInjectorError(Platform: core)[AppComponent -> InjectionToken I18n]: 
    NullInjectorError: No provider for InjectionToken I18n!
    at NullInjector.get (core.js:778)
    at resolveToken (core.js:2564)
    at tryResolveToken (core.js:2490)
    at StaticInjector.get (core.js:2353)
    at resolveToken (core.js:2564)
    at tryResolveToken (core.js:2490)
    at StaticInjector.get (core.js:2353)
    at resolveNgModuleDep (core.js:26403)
    at NgModuleRef_.get (core.js:27491)
    at resolveNgModuleDep (core.js:26403)
    at resolvePromise (zone-evergreen.js:797)
    ...
Run Code Online (Sandbox Code Playgroud)

对我们的意图说几句(以防有更好的解决方案,我们还没有找到):我们想要像“微前端”这样的东西。我们想要一个集成或主应用程序,它提供应用程序的核心应用程序和基本布局。我们有多个“子系统”,即为特定业务逻辑提供 GUI 的小应用程序(是的,一种经典的微服务架构)。所以根据这个,GUI在构建子系统的时候就已经构建好了。该子系统将 GUI 作为单个包提供,集成应用程序应加载该包并将其安装到应用程序中。