【问题标题】:FeatureModule fails during an AOT build when static forRoot has arguments当静态 forRoot 有参数时,FeatureModule 在 AOT 构建期间失败
【发布时间】:2018-05-21 01:31:02
【问题描述】:

我在使用 Angular@5.1.0 时遇到了 AOT 构建问题。

错误是:

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

feature.module.ts

@NgModule({
    imports: [
        BrowserModule,
        RouterModule.forRoot([])
    ],
    declarations: [
        ...    
    ],
    exports: [
        ...      
    ]
})
export class FeatureModule{
    static forRoot(items:any[]): ModuleWithProviders {
        const routes:Routes = items.map(t=> {
            return { path: t.name, component: t.component };
        });

        return {
            ngModule: FeatureModule, 
            providers: [
                provideRoutes(routes)
            ]
        }
    }
}

这可以在非 aot 构建中成功编译。这似乎只是 AOT 构建的问题。

为什么会发生这个错误?

【问题讨论】:

  • 这不会解决您的问题,但可能会让您更接近解决问题。 Angular 5.1 今天与 CLI 1.6 一起发布。已解决的问题之一是Improved decorator error messages。也许尝试升级到最新版本,看看你是否能找到解决这个问题的方法。很抱歉没有提供更多帮助。 blog.angular.io/angular-5-1-more-now-available-27d372f5eb4e
  • 谢谢,感谢您的建议。我将尝试运行 CLI 1.6 以查看错误是否提供更多信息。
  • 最新的@angular/cli中仍然存在错误。
  • 您是否尝试删除var routes - data 并使用providers: [provideRoutes(data)]
  • Feature 模块中你写了imports: [ RouterModule.forRoot() ], 不应该是forRoot([]) 吗?可以设置复制吗?

标签: angular aot


【解决方案1】:

好的,我花了一段时间才弄清楚这一点。 TLDR:forRoot 方法必须非常简单,否则 AOT 编译器会报错。

为了简单起见,我必须:

  1. forRoot 方法中删除分支逻辑和函数调用。

  2. 实现将项目映射到路由到工厂提供程序的逻辑,而不是将其内联到 forRoot 方法中。

  3. 使用Router.resetConfig 在工厂实现中动态添加路由。

  4. 添加一个 ANALYZE_FOR_ENTRY_COMPONENTS 提供程序,以便将传入的任何组件作为模块的一部分自动添加到 entryComponents

  5. RouterModule.forChild([]) 导入FeatureModule,因为我使用来自@angular/router 的组件。

  6. RouterModule.forRoot([]) 导入AppModule,因为它提供了应用程序范围的Router 服务。

最终解决方案

export const Items = new InjectionToken<any[]>('items');
export function InitMyService(router:Router, items:any[]) {
     var routes:Routes =  items.map(t=> { return { path: t.name, component: t.component, outlet: 'modal' }});
     var r = router.config.concat(routes);
     router.resetConfig(r);        
     return new MyService(router);
}


@NgModule({
    imports: [
        CommonModule,
        RouterModule.forChild([])
    ],
    declarations: [
        MyComponent
    ],
    exports: [
        MyComponent
    ],
    providers: [

    ]
})
export class FeatureModule {
    static forRoot(items:any[]): ModuleWithProviders {
        return {
            ngModule: FeatureModule, 
            providers: [
                { provide: Items, useValue: items},
                { provide: ANALYZE_FOR_ENTRY_COMPONENTS, multi: true, useValue: items},
                { provide: MyService, useFactory: InitMyService, deps:[Router, Items] }
            ]
        }
    }
}

app.module.ts

@NgModule({
  imports:      [ 
      BrowserModule,
      RouterModule.forRoot([]),
      FeatureModule.forRoot([{name: 'test', component: TestComponent}])
    ],
  declarations: [ AppComponent, TestComponent ],
  bootstrap:    [ AppComponent ],
  providers: [
  ],
  exports: [AppComponent]
})
export class AppModule {
}

解决这个问题的关键是意识到RouterModule.forChild() 没有注册任何路由器服务。这是有意的,以便任何模块都可以导入 RouterModule 并利用其组件,而无需实际注册任何服务。在 AppModule 级别,我仍然需要通过将 RouterModule.forRoot() 导入 AppModule 来将 Router 服务注册为单例。

【讨论】:

  • 你能分享你的 MyService 课程吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-05
  • 1970-01-01
  • 2012-04-21
  • 2020-12-02
  • 2018-05-07
  • 2017-10-22
相关资源
最近更新 更多