动态模块/服务配置和AOT [英] Dynamic module/service configuration and AOT

查看:84
本文介绍了动态模块/服务配置和AOT的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要根据运行时开关动态配置一些Angular服务.在AOT推出之前的几天里,我使用以下代码将其运行:

@NgModule({
  imports: [HttpModule],
  providers: []
})
export class MyModule {
  static forRoot(config: MyConfiguration): ModuleWithProviders {
    return {
      ngModule: MyModule,
      providers: [
        SomeService,
        {
          provide: SomeOtherService,
          useFactory: (some: SomeService, http: Http) => {
            switch (config.type) {
              case 'cloud':
                return new SomeOtherService(new SomethingSpecificForCloud());
              case 'server':
                return new SomeOtherService(new SomethingSpecificForServer());
            }
          },
          deps: [SomeService, Http]
        },

      ]
    };
  }
}

然后在我的AppModule中,将其导入为MyModule.forRoot(myConfig).

在更新CLI和Angular时,由于无法进行静态分析,因此不再编译.我知道为什么,但是我仍然不确定解决该问题的正确方法.

我是否首先滥用了这种forRoot()方法?您如何编写模块,以便根据运行时开关,它们产生不同的服务?

我找到了一种实现它的方法:通过提供程序公开配置,然后注入静态"工厂功能.上面的代码如下所示:

// Necessary if MyConfiguration is an interface
export const MY_CONFIG = new OpaqueToken('my.config');

// Static factory function
export function someOtherServiceFactory(config: MyConfiguration,some: SomeService, http: Http) {
  switch (config.type) {
    case 'cloud':
      return new SomeOtherService(new SomethingSpecificForCloud());
    case 'server':
      return new SomeOtherService(new SomethingSpecificForServer());
  }
}

@NgModule({
  imports: [HttpModule],
  providers: []
})
export class MyModule {
  static forRoot(config: MyConfiguration): ModuleWithProviders {
    return {
      ngModule: MyModule,
      providers: [
        SomeService,
        { provide: MY_CONFIG, useValue: config },
        {
          provide: SomeOtherService,
          useFactory: someOtherServiceFactory,
          deps: [MY_CONFIG, SomeService, Http]
        },

      ]
    };
  }
}

一切正常,但是我仍然想知道这是否是个好主意,或者我做错了什么,应该采取一种完全不同的方法来解决这个问题.


我找到了另一种解决方案:

  1. 使用Angular CLI环境.
  2. 为具有不同环境的不同实现或依赖关系的服务创建抽象类/接口.
  3. 从每个环境文件中导出正确的类型(谁说它必须只是一个普通的JS对象?).
  4. 在模块提供者定义中,从环境中导入 .
  5. 在编译时,CLI环境将链接正确的内容.

更多信息和示例项目,位于 解决方案

I found one way to achieve it: Expose the configuration via a provider, then have injected to a "static" factory function. The code above would look like this:

// Necessary if MyConfiguration is an interface
export const MY_CONFIG = new OpaqueToken('my.config');

// Static factory function
export function someOtherServiceFactory(config: MyConfiguration,some: SomeService, http: Http) {
  switch (config.type) {
    case 'cloud':
      return new SomeOtherService(new SomethingSpecificForCloud());
    case 'server':
      return new SomeOtherService(new SomethingSpecificForServer());
  }
}

@NgModule({
  imports: [HttpModule],
  providers: []
})
export class MyModule {
  static forRoot(config: MyConfiguration): ModuleWithProviders {
    return {
      ngModule: MyModule,
      providers: [
        SomeService,
        { provide: MY_CONFIG, useValue: config },
        {
          provide: SomeOtherService,
          useFactory: someOtherServiceFactory,
          deps: [MY_CONFIG, SomeService, Http]
        },

      ]
    };
  }
}

It works and all, but I would still be very interested in knowing whether this is actually a good idea, or if I'm doing something terribly wrong and should be taking a completely different approach to solving this problem.


I found another solution:

  1. Use Angular CLI environments.
  2. Create an abstract classes/interfaces for the services with different implementations or dependencies for different environments.
  3. Export the right type from each enviromnent file (who said it has to only be a plain JS object?).
  4. In the module provider definition, import from the environment.
  5. At compile time, CLI environments will make the right thing get linked.

More information and sample project at my blog.

这篇关于动态模块/服务配置和AOT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆