【问题标题】:Get injector from module in angular 8从角度 8 的模块中获取注入器
【发布时间】:2019-07-16 11:09:43
【问题描述】:

问题:

我正在为 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 添加的静态模块类属性,具有工厂、提供者和导入属性。

来源:

【问题讨论】:

    标签: angular angular8 angular-compiler angular-ivy


    【解决方案1】:

    我不会说访问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;
    }
    

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

    【讨论】:

    • 感谢您提供如此重要的答案!我已经尝试过您所描述的内容,但是当我为导入的模块调用 createInjector 时 - 对于导入模块中的任何提供程序和声明,我都有一个错误 Error: Can't resolve all parameters for...。我应该启用 IVY 以使此功能正常工作吗? "angularCompilerOptions": { "enableIvy": true},
    • 当然,你应该,这仅适用于常春藤,你刚刚在你的问题中提到你正在使用常春藤:D
    • 知道了,再次感谢。目前,我们只是为搬到 IVY 做准备。因此,一旦我们使用它,我将能够使用该解决方案:)
    • @JackHudzenko 可能......?
    猜你喜欢
    • 2017-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    • 1970-01-01
    • 2019-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多