使用静态方法 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