0

Please suggest a better title if you can think of one

We have a multi-module enterprise application that is written in Angular 2

To handle multi-customer use of our system we have an override strategy for images and such. Basically a map of strings to file locations. To switch which assets get overridden we pass the map to override the existing map into the .forAssets() method below. This pattern was taken from the Angular 2 RouterModule source code.

This issue is when AOT compiling we get the error

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

Top Level Module

@NgModule({
  imports: [
    AssetsModule.forAssets(),
    SomeModule
  ]
})
export class MainModule{
  public ngDoBootstrap(ref: ApplicationRef){
    ref.bootstrap(StartupComponent);
  }
}

platformBrowser().bootstrapModuleFactory(MainModuleNgFactory);

Some Module

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    AssetsModule,
    RouterModule.forRoot(SOME_ROUTES, {useHash: true})
  ],
  providers: [
    ...
  ],
  schemas:[
    NO_ERRORS_SCHEMA
  ],
  bootstrap: [StartupComponent]
})
export class SomeModule {}

Copying the Angular 2 RouterModule.forChild() pattern that they used for overrides. I have created a similar override structure for our 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
    };
  }
}

ASSETS is an OpaqueToken

This error, as unhelpful as it is, only occurs when the line AssetsModule.forAssets() is present in the top level module. If I comment it out or remove it the compilation succeeds.

1
  • I'm still not sure how exactly this part of AoT works. But have you tried to simplify forAssets contents to bare minimum to see what will happen? Notice that forChild you're referring to calls only provideRoutes, which is named exported function (as the error suggests), while forAssets has pretty much inside, including an anonymous arrow. Commented Oct 17, 2016 at 2:06

2 Answers 2

4

Your static function in the module class can only have 1 statement, and that statement has to be a return.

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

Sign up to request clarification or add additional context in comments.

1 Comment

Is this documented somewhere?
1

Looks like you are passing in a list of possible override types for Assets that you use to map back to dynamic overrides.

The AoT compiler does not allow us to build the list of providers dynamically like this. I think the only way to add any sort of logic when defining providers is by using a factory

Maybe you can re-architect your code to use a factory that determines which override to use.

    //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 could be an abstract class or something that you inherit and pass in to the forAssets method.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.