当静态forRoot具有参数时,在AOT构建期间FeatureModule失败

时间:2017-12-07 02:31:51

标签: angular aot

我使用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构建的一个问题。

为什么会发生这种错误?

1 个答案:

答案 0 :(得分:4)

好的,我花了一段时间才弄明白这一点。 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服务。

  7. 最终解决方案

    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级别,我仍然需要通过将Router导入AppModule来将RouterModule.forRoot()服务注册为单身人士。