使用静态方法 ModuleWithProviders 覆盖时 AOT 编译出错
Error with AOT compilation when using a static method ModuleWithProviders override
如果你能想到一个更好的标题,请提出一个更好的标题
我们有一个用 Angular 2
编写的 multi-module 企业应用程序
为了处理 multi-customer 对我们系统的使用,我们有一个覆盖图像等的策略。基本上是字符串到文件位置的映射。要切换哪些资产被覆盖,我们将覆盖现有地图的地图传递到下面的 .forAssets()
方法中。此模式取自 Angular 2 RouterModule
源代码。
这个问题是AOT编译报错
Error: Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol MainModule in /Users/--/--/my-module/index.ts, resolving symbol MainModule in /Users/--/--/common-module/index.ts
顶级模块
@NgModule({
imports: [
AssetsModule.forAssets(),
SomeModule
]
})
export class MainModule{
public ngDoBootstrap(ref: ApplicationRef){
ref.bootstrap(StartupComponent);
}
}
platformBrowser().bootstrapModuleFactory(MainModuleNgFactory);
一些模块
@NgModule({
declarations: [
...
],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
AssetsModule,
RouterModule.forRoot(SOME_ROUTES, {useHash: true})
],
providers: [
...
],
schemas:[
NO_ERRORS_SCHEMA
],
bootstrap: [StartupComponent]
})
export class SomeModule {}
正在复制他们用于覆盖的 Angular 2 RouterModule.forChild()
模式。我为 AssetsModule
创建了一个类似的覆盖结构
资产模块
@NgModule({
declarations: [
ImgDirective
],
providers: [
AssetService
]
})
export class AssetsModule{
public static forAssets(...overrides: any[]): ModuleWithProviders{
const providers = [{provide: ASSETS, multi: true, useValue: DefaultAssets}];
providers.concat(overrides.map(override => {
return {provide: ASSETS, multi: true, useValue: override};
}));
return {
ngModule: AssetsModule,
providers: providers
};
}
}
ASSETS
是一个 OpaqueToken
这个错误虽然毫无用处,但仅当行 AssetsModule.forAssets()
出现在顶级模块中时才会发生。如果我将其注释掉或删除,则编译成功。
看起来您正在为 Assets
传递一个可能的覆盖类型列表,您可以使用它映射回动态覆盖。
AoT 编译器不允许我们像这样动态构建提供者列表。我认为在定义提供者时添加任何逻辑的唯一方法是使用工厂
也许您可以重新构建代码以使用一个工厂来确定要使用哪个覆盖。
//factory function
export function myFactory(override: WhichAssetToUse): any {
if(override.type === 'type1'){
return {a:1};// some override
}
return {b:1};// a different override
}
public static forAssets(whichAsset: WhichAssetToUse):ModuleWithProviders{
providers:[
{provide: WhichAssetToUse, useClass: whichAsset},
{provide: Asset,
useFactory: myFactory,
deps: [WhichAssetToUse]}]
}
WhichAssetToUse
可以是抽象 class 或您继承并传递给 forAssets 方法的东西。
模块 class 中的静态函数只能有 1 个语句,并且该语句必须是 return
.
https://github.com/angular/angular/blob/master/tools/@angular/tsc-wrapped/src/collector.ts#L54-L72
如果你能想到一个更好的标题,请提出一个更好的标题
我们有一个用 Angular 2
编写的 multi-module 企业应用程序为了处理 multi-customer 对我们系统的使用,我们有一个覆盖图像等的策略。基本上是字符串到文件位置的映射。要切换哪些资产被覆盖,我们将覆盖现有地图的地图传递到下面的 .forAssets()
方法中。此模式取自 Angular 2 RouterModule
源代码。
这个问题是AOT编译报错
Error: Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol MainModule in /Users/--/--/my-module/index.ts, resolving symbol MainModule in /Users/--/--/common-module/index.ts
顶级模块
@NgModule({
imports: [
AssetsModule.forAssets(),
SomeModule
]
})
export class MainModule{
public ngDoBootstrap(ref: ApplicationRef){
ref.bootstrap(StartupComponent);
}
}
platformBrowser().bootstrapModuleFactory(MainModuleNgFactory);
一些模块
@NgModule({
declarations: [
...
],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
AssetsModule,
RouterModule.forRoot(SOME_ROUTES, {useHash: true})
],
providers: [
...
],
schemas:[
NO_ERRORS_SCHEMA
],
bootstrap: [StartupComponent]
})
export class SomeModule {}
正在复制他们用于覆盖的 Angular 2 RouterModule.forChild()
模式。我为 AssetsModule
资产模块
@NgModule({
declarations: [
ImgDirective
],
providers: [
AssetService
]
})
export class AssetsModule{
public static forAssets(...overrides: any[]): ModuleWithProviders{
const providers = [{provide: ASSETS, multi: true, useValue: DefaultAssets}];
providers.concat(overrides.map(override => {
return {provide: ASSETS, multi: true, useValue: override};
}));
return {
ngModule: AssetsModule,
providers: providers
};
}
}
ASSETS
是一个 OpaqueToken
这个错误虽然毫无用处,但仅当行 AssetsModule.forAssets()
出现在顶级模块中时才会发生。如果我将其注释掉或删除,则编译成功。
看起来您正在为 Assets
传递一个可能的覆盖类型列表,您可以使用它映射回动态覆盖。
AoT 编译器不允许我们像这样动态构建提供者列表。我认为在定义提供者时添加任何逻辑的唯一方法是使用工厂
也许您可以重新构建代码以使用一个工厂来确定要使用哪个覆盖。
//factory function
export function myFactory(override: WhichAssetToUse): any {
if(override.type === 'type1'){
return {a:1};// some override
}
return {b:1};// a different override
}
public static forAssets(whichAsset: WhichAssetToUse):ModuleWithProviders{
providers:[
{provide: WhichAssetToUse, useClass: whichAsset},
{provide: Asset,
useFactory: myFactory,
deps: [WhichAssetToUse]}]
}
WhichAssetToUse
可以是抽象 class 或您继承并传递给 forAssets 方法的东西。
模块 class 中的静态函数只能有 1 个语句,并且该语句必须是 return
.
https://github.com/angular/angular/blob/master/tools/@angular/tsc-wrapped/src/collector.ts#L54-L72