Angular aot编译中的装饰器不支持如何摆脱函数调用?

Ani*_*oui 12 javascript highcharts typescript angular-cli angular

我正在测试Highcharts Angular2x Wrapper.首先,我使用Angular CLI(1.6.1)"ng serve"并使用Chrome分析性能时没有任何问题.然后,我尝试使用提前编译来查看它如何影响性能.

所以,使用:

ng serve --aot
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

ERROR in Error during template compile of 'AppModule'
  Function calls are not supported in decorators but 'ChartModule' was called.
Run Code Online (Sandbox Code Playgroud)

现在,我知道aot为模块生成工厂代码,并以某种方式"转换"模板到VanillaJS,这里的事情有点棘手,我无法理解ngc将如何为需要外部库的模块生成工厂代码.

我得到了这个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 { }
Run Code Online (Sandbox Code Playgroud)

我的Package.json依赖项:

"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"
  }
Run Code Online (Sandbox Code Playgroud)

我的问题是:我能在这里做些什么来避免上述编译错误吗?谁能解释为什么会这样?(可选的)

das*_*dsa 8

这通常是 angular 的问题。Angular 编译器希望forRoot代码完全静态。

例如,在以下代码中,即使是静态变量的赋值也会导致此错误:

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

如果您不是库的创建者,除了尝试上述特定于库的解决方案外,您无能为力。但是,如果您是库创建者,则可以尝试以下静态方法:

  1. 创建注入令牌:

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

  2. 在您的库模块中提供令牌

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

  1. 在其他地方使用 DI 使用令牌:

static forRoot(config: MyConfig): ModuleWithProviders {
            return {
                ngModule: HttpTrackerLibModule,
                providers: [{
                    provide: USER_OPTIONS,
                    useValue: config
                }],
            };
        }
Run Code Online (Sandbox Code Playgroud)


Ani*_*oui 5

这里提到Github问题。以下解决方案为我工作。

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 { }
Run Code Online (Sandbox Code Playgroud)


Dec*_*ded 5

如果它可以帮助人们克服错误,我想提出一个额外的答案。我在Angular 11上有两个几乎相同的应用程序,它们共享同一个库模块,该模块具有static forRoot用于自定义注入配置的方法声明。

\n
@NgModule()\nexport class TheModule {\n  static forRoot(...) {\n   ... \n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

应用程序 A 按预期工作,应用程序 B 引发了相关错误。\n当然,我的两个应用程序本质上是不同的,因此这将其范围缩小到infrastructureconfiguration差异。

\n

调查

\n

查看共享模块的compiled代码,例如the-module.module.d.ts看看是否存在差异:

\n

从工作应用范围来看:

\n
// the-module.module.d.ts\nimport * ...\n...\n\nexport declare class TheModule {\n    static \xc9\xb5mod: \xc9\xb5ngcc0.\xc9\xb5\xc9\xb5NgModuleDefWithMeta<TheModule, [typeof \xc9\xb5ngcc4.AComponent, ...]\n    static \xc9\xb5inj: \xc9\xb5ngcc0.\xc9\xb5\xc9\xb5InjectorDef<TheModule>;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请注意emod(模块)和einj(注入)定义。

\n

从损坏的应用程序范围来看

\n

它缺少这些定义:

\n
// the-module.module.d.ts\nexport declare class TheModule {\n}\n
Run Code Online (Sandbox Code Playgroud)\n

好吧,为什么损坏的应用程序的模块是空的!?一定是和编译有关的东西!看根tsconfig.json

\n

对于损坏的应用程序:

\n

angularCompilerOptions启用了以下设置:

\n
// woops, remove this to use the newer compiler for angular versions > 9.0\n"angularCompilerOptions": {\n    "enableIvy": false\n }\n
Run Code Online (Sandbox Code Playgroud)\n

这是前几天留下来的。删除此错误后,错误消失了,并且它使编译器能够与共享库模块交互并填充其类型。

\n

编译 AOT 时,请查看编译器选项文档:https://angular.io/guide/angular-compiler-options以查看详细信息。\n@AngularJs 打印的错误消息,将其视为decorator“副作用” ”,且无关。

\n