从角度8的模块中获取进样器

时间:2019-07-16 11:09:43

标签: angular angular8 angular-compiler angular-ivy

问题:

我正在为angular的非路由模块设置延迟加载。在版本7中,我使用了NgModuleFactoryLoader及其功能load来延迟加载模块并获取该模块的第一个入口点(服务用尽)

this.loader.load('path-to-module')
  .then(factory => {
    const module = factory.create(this._injector);
    return module.injector.get(EntryService);
  });

但是在Angular 8中,NgModuleFactoryLoader已过时,因此我不得不以这种方式加载模块:

import('path-to-module')
  .then(m => m.MyModule)
  .then(myModule => {
    ...
});

这里的问题是我无法在新的延迟加载中检索工厂并在此处获取提供者(IVY的想法之一-没有工厂)。

我已经尝试过的方法:

第一个解决方案(仅适用于不适合我们的JIT编译器,因为我将AOT编译器用于产品)

import('path-to-module')
  .then(m => m.MyModule)
  .then(myModule => {
    return this._compiler.compileModuleAsync(myModule)
      .then(factory => {
        const module = factory.create(this._injector);
        return module.injector.get(EntryService);
      });
});

第二个解决方案(脏且未完全检查。它使用的是ngInjectorDef,这是IVY的新功能,尚无任何描述的API):

import('path-to-module')
  .then(m => m.MyModule)
  .then(myModule => {
    const providers = myModule['ngInjectorDef'].providers; // Array<Providers>
    ... find EntryService in providers
});

ngInjectorDef-是静态模块类属性,它是由angular添加的,并且具有工厂,提供者和导入的属性。

来源:

1 个答案:

答案 0 :(得分:2)

我不会说访问ngInjectorDef属性是“肮脏的骇客”。是的,它没有在任何地方进行文档记录,因为正如Igor Minar所说,Ivy是Angular 8的可选预览。但是Viktor Savkin的某些文章中已经提到了很多私有功能,例如directiveInject

您不应在providers属性中搜索服务。想象有20个以上的提供程序,并且EntryService的名称在生产中将被缩小为tk之类。

如果使用Ivy,则有一个名为createInjector的私有函数,该函数接受模块构造函数作为参数。

@Injectable()
export class EntryService {
  public logFromEntryService(): void {
    console.log('Logging from EntryService...');
  }
}

@NgModule({
  providers: [EntryService]
})
export class EntryModule {
  public static getEntryService: () => EntryService = null;

  constructor(injector: Injector) {
    EntryModule.getEntryService = () => injector.get(EntryService);
  }
}

假设您有这样的代码,让我们使用动态导入来加载此EntryModule

import { ɵcreateInjector as createInjector } from '@angular/core';

export class AppComponent {
  constructor(private injector: Injector) {
    this.loadEntryModule();
  }

  private async loadEntryModule(): Promise<void> {
    const { EntryModule } = await import('./entry.module');
    createInjector(EntryModule, this.injector);
    EntryModule.getEntryService().logFromEntryService();
  }
}

createInjector用于在实例化后实例化EntryModule-getEntryService静态方法不等于null

我们还可以公开injector属性,例如:

public static injector: Injector = null;

constructor(injector: Injector) {
  EntryModule.injector = injector;
}

这可能被视为服务定位器,这是一种反模式。但是取决于你!