【问题标题】:Dynamic module/service configuration and AOT动态模块/服务配置和 AOT
【发布时间】:2017-06-29 18:54:27
【问题描述】:

我需要动态配置一些 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() 方法?您如何编写模块,以便根据运行时开关产生不同的服务?

【问题讨论】:

    标签: angular angular2-aot


    【解决方案1】:

    我找到了一种实现方法:通过提供者公开配置,然后注入“静态”工厂函数。上面的代码如下所示:

    // 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 环境会链接正确的东西。

    更多信息和示例项目请访问my blog

    【讨论】:

    • 我认为这是唯一的选择。 1 备注:从 v4 开始,您应该使用 InjectionToken 而不是 OpaqueToken
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-23
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    • 2021-11-12
    • 1970-01-01
    • 2021-10-22
    相关资源
    最近更新 更多