简体   繁体   English

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

[英]Get injector from module in angular 8

Problem: 问题:

I am setting up lazy loading for non-routed module in angular. 我正在为angular的非路由模块设置延迟加载。 At version 7 I used NgModuleFactoryLoader and it's function load to lazy load module and get first entry point to the module (service in out case) 在版本7中,我使用了NgModuleFactoryLoader并将其功能load到延迟加载模块并获取该模块的第一个入口点(服务在外情况下)

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

But in Angular 8 NgModuleFactoryLoader is deprecated so instead I have to load module in that way: 但是在Angular 8中, NgModuleFactoryLoader被弃用了,所以我不得不以这种方式加载模块:

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

The problem here that I can not retrieve factory and get provider here in a new lazy loading (one of ideas of IVY - no factories). 这里的问题是我无法在新的延迟加载中检索工厂并在此处获取提供者(IVY的想法之一-没有工厂)。

What I have already tried: 我已经尝试过的:

First solution (work only with JIT compiler which is not suits us as I am using AOT compiler for prod) 第一个解决方案(仅适用于不适合我们的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);
      });
});

Second solution (dirty and not fully checked. It is using ngInjectorDef which is new feature of IVY and has no any described API yet): 第二种解决方案(脏且未完全检查。它使用的是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 - is a static module class property which is added by angular and has properties factory, providers and imports. ngInjectorDef是一个静态模块类属性,该属性是由angular添加的,并且具有工厂,提供者和进口的属性。

Sources: 资料来源:

I wouldn't say that accessing the ngInjectorDef property is a "dirty hack". 我不会说访问ngInjectorDef属性是“肮脏的黑客”。 Yes, it is not documented anywhere because, as Igor Minar said, Ivy is opt-in preview in Angular 8. But a lot of private functions were already mentioned in some articles of Viktor Savkin, for example directiveInject . 是的,它没有在任何地方进行文档记录,因为正如Igor Minar所说,Ivy是Angular 8的选择性加入预览。但是Viktor Savkin的某些文章中已经提到了很多私有函数,例如directiveInject

You should not search for your service in the providers property. 您不应在providers属性中搜索服务。 Imagine that there are 20+ providers and also the EntryService name will be minified in the production to something like t or k . 想象一下,有20多个提供者, EntryService名称在生产中将EntryService tk

If you use Ivy - there is a private function called createInjector , that accepts module constructor as an argument. 如果使用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);
  }
}

Assume you've got such code, let's use a dynamic import to load this EntryModule : 假设您有这样的代码,让我们使用动态导入来加载此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 is used for instantiating EntryModule , after instanting - the getEntryService static method doesn't equal null . createInjector用于实例化EntryModule ,instanting之后-该getEntryService静态方法并不等于null

We could also expose the injector property, like: 我们还可以公开injector属性,例如:

public static injector: Injector = null;

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

This might be treated as a service locator, which is kind of anti-pattern. 可以将其视为服务定位器,这是一种反模式。 But up to you! 但是取决于你!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM