2

问题:

我正在为角度的非路由模块设置延迟加载。在我使用的第 7 版中NgModuleFactoryLoader,它的功能load是延迟加载模块并获取模块的第一个入口点(以防万一)

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

但是在 Angular 8NgModuleFactoryLoader中已弃用,所以我必须以这种方式加载模块:

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);
      });
});

第二种解决方案(肮脏且未完全检查。它正在使用ngInjectorDefIVY 的新功能并且还没有任何描述的 API):

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

ngInjectorDef- 是一个静态模块类属性,由 Angular 添加,具有工厂、提供者和导入属性。

资料来源:

4

1 回答 1

4

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

providers您不应该在物业中搜索您的服务。想象一下,有 20 多个提供者,并且EntryService名称将在生产中缩小为类似tor的名称k

如果您使用 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;
}

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

于 2019-07-23T21:04:07.657 回答