动态模块/服务配置和AOT [英] Dynamic module/service configuration and 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]
},
]
};
}
}
一切正常,但是我仍然想知道这是否是个好主意,或者我做错了什么,应该采取一种完全不同的方法来解决这个问题.
我找到了另一种解决方案:
- 使用Angular CLI环境.
- 为具有不同环境的不同实现或依赖关系的服务创建抽象类/接口.
- 从每个环境文件中导出正确的类型(谁说它必须只是一个普通的JS对象?).
- 在模块提供者定义中,从环境中导入 .
- 在编译时,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:
- Use Angular CLI environments.
- Create an abstract classes/interfaces for the services with different implementations or dependencies for different environments.
- Export the right type from each enviromnent file (who said it has to only be a plain JS object?).
- In the module provider definition, import from the environment.
- At compile time, CLI environments will make the right thing get linked.
More information and sample project at my blog.
这篇关于动态模块/服务配置和AOT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!