Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get rid of Function calls are not supported in decorators in Angular aot compiling?

I am testing a Highcharts Angular2x Wrapper. At first, I had no problem using Angular CLI (1.6.1) "ng serve" and profiling performance with Chrome. Then, i tried to use ahead-of-time compiling to see how that affects the performance.

So, using:

ng serve --aot

I get the following error:

ERROR in Error during template compile of 'AppModule'
  Function calls are not supported in decorators but 'ChartModule' was called.

Now, i know that aot generates factory code for modules and somehow "transformes" templates to VanillaJS, things get a bit tricky here and i couldn't understand how ngc is going to generate factory code for a module that requires an external library.

I got this App.Module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ChartModule } from 'angular2-highcharts';

import { AppComponent } from './app.component';

declare var require: any;
export function getHighchartsModule() {
  return  require('highcharts');
}

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ChartModule.forRoot(getHighchartsModule) // This causes the error
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

My Package.json dependencies :

"dependencies": {
    "@angular/animations": "^5.0.0",
    "@angular/common": "^5.0.0",
    "@angular/compiler": "^5.0.0",
    "@angular/core": "^5.0.0",
    "@angular/forms": "^5.0.0",
    "@angular/http": "^5.0.0",
    "@angular/platform-browser": "^5.0.0",
    "@angular/platform-browser-dynamic": "^5.0.0",
    "@angular/router": "^5.0.0",
    "angular2-highcharts": "^0.5.5",
    "core-js": "^2.4.1",
    "rxjs": "^5.5.2",
    "zone.js": "^0.8.14"
  }

My questions are : Is there anything i can do here to avoid the mentioned compiling error ? Can anyone explain why does this happen ? (optional)

like image 773
Anis Tissaoui Avatar asked Jan 16 '18 14:01

Anis Tissaoui


2 Answers

This is a problem with angular in general. Angular compiler wants the forRoot code to be completely static.

As an example, in the following code even the assignment of the static variable will cause this error:

static forRoot(config: MyConfig): ModuleWithProviders {
    MyConfigService.config = config;// This line with cause an error
    return {
      ngModule: HttpTrackerLibModule,
    };
  }

If you are not library creator there is nothing much you can do but try library-specific solutions like the one above. But if you are a library creator you can try a static approach as follows:

  1. Create an injection token:

    export const USER_OPTIONS = new InjectionToken<MyConfig>('USER_OPTIONS');

  2. Provide the token in your library Module

static forRoot(config: MyConfig): ModuleWithProviders {
            return {
                ngModule: HttpTrackerLibModule,
                providers: [{
                    provide: USER_OPTIONS,
                    useValue: config
                }],
            };
        }
  1. Use the token using DI elsewhere:

export class ConfigService {
  constructor(@Inject(USER_OPTIONS) private _config: MyConfig) {

  }
}
like image 172
dasfdsa Avatar answered Oct 12 '22 12:10

dasfdsa


Mentioning the Github issue here. The following solution worked for me.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

// Angular Highcharts Imports
import {HighchartsStatic} from 'angular2-highcharts/dist/HighchartsService'; 
import { ChartModule } from 'angular2-highcharts';

// Factory Function
export function highchartsFactory() {
  var hc = require('highcharts');
  return hc;
}

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ChartModule // Import Module Here
  ],
  providers: [ // Provide Service Here
    {
      provide: HighchartsStatic,
      useFactory: highchartsFactory 
    },
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
like image 32
Anis Tissaoui Avatar answered Oct 12 '22 12:10

Anis Tissaoui