使用静态方法ModuleWithProviders覆盖时AOT编译出错

时间:2016-10-17 01:18:59

标签: angular typescript angular-cli

如果您能想到一个

,请建议更好的标题

我们有一个用Angular 2编写的多模块企业应用程序

为了处理多用户对我们系统的使用,我们对图像等采用了覆盖策略。基本上是字符串到文件位置的映射。要切换哪些资产被覆盖,我们会通过地图将现有地图覆盖到下面的.forAssets()方法中。此模式取自Angular 2 RouterModule源代码。

这个问题是当AOT编译我们得到错误

  

错误:静态解析符号值时出错。不支持函数调用。考虑使用对导出函数的引用替换函数或lambda,解析/Users/--/-/my-module/index.ts中的符号MainModule,解决/ Users / - / - / common-中的符号MainModule模块/ 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

创建了一个类似的覆盖结构

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
    };
  }
}

ASSETSOpaqueToken

此错误虽然无用,但只会在顶级模块中存在行AssetsModule.forAssets()时发生。如果我将其注释掉或删除它,编译就会成功。

2 个答案:

答案 0 :(得分:3)

模块类中的静态函数只能有1个语句,该语句必须是return

https://github.com/angular/angular/blob/master/tools/@angular/tsc-wrapped/src/collector.ts#L54-L72

答案 1 :(得分:1)

您似乎正在传递用于映射回动态替换的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可以是一个抽象类,也可以是你继承并传入forAssets方法的东西。