Angular 6编译报错:Cannot read property 'loadChildren' of null
我之前碰到过几例Angular 6升级后类似的路由编译问题,结合你的代码和错误提示来看,核心问题大概率出在Angular 6对路由静态分析的严格性提升,以及可能存在的懒加载语法不兼容上,具体原因和解决思路如下:
问题根源
Angular 6的AOT(提前编译)机制相比Angular 5做了不少优化,但也对路由定义的静态可解析性要求更高。你的错误提示是Cannot read property 'loadChildren' of null,结合adminRoutes移除后错误消失的现象,推测:
- 你的
adminModuleRoutes包含的子路由(比如rolesRoutes、userRoutes等)中,存在使用Angular 5旧版懒加载语法的配置; - 首次编译时,AOT编译器无法正确解析跨模块导出的路由数组(
adminRoutes是从@ui/admin-module导出的),导致路由对象被解析为null,进而触发loadChildren的读取错误; - 二次编译时,因为模块已经被部分解析或缓存,编译器能正确识别路由结构,所以错误消失。
具体解决方案
1. 升级懒加载语法到Angular 6标准
Angular 6引入了动态导入的懒加载语法,替代了旧的字符串拼接方式,这是最常见的触发此类错误的原因。检查所有子路由中的懒加载配置,将旧语法:
{ path: 'roles', loadChildren: './roles/roles.module#RolesModule' }
替换为Angular 6+的新语法:
{ path: 'roles', loadChildren: () => import('./roles/roles.module').then(m => m.RolesModule) }
2. 改用路由模块导入替代数组扩展
你当前通过扩展adminRoutes数组的方式合并路由,这种跨模块的数组导出在Angular 6的AOT编译下容易出现静态解析问题。建议改为在Admin模块内创建独立的路由模块,通过模块导入的方式整合路由:
步骤1:创建AdminRoutingModule
在Admin模块目录下新建admin-routing.module.ts:
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { LayoutComponent } from './core'; import { designationRoutes } from './modules/designations'; import { organizationRoutes } from './modules/organizations'; import { rolesRoutes } from './modules/roles'; import { templateRoutes } from './modules/templates'; import { userRoutes } from './modules/users'; const adminModuleRoutes: Routes = [ ...rolesRoutes, ...userRoutes, ...designationRoutes, ...organizationRoutes, ...templateRoutes ]; const adminRoutes: Routes = [ { path: 'admin', component: LayoutComponent, children: [ { path: '', pathMatch: 'full', redirectTo: 'roles' }, ...adminModuleRoutes ] } ]; @NgModule({ imports: [RouterModule.forChild(adminRoutes)], exports: [RouterModule] }) export class AdminRoutingModule {}
步骤2:在AdminModule中导入路由模块
修改AdminModule的代码,引入并导入AdminRoutingModule:
import { NgModule, Provider } from '@angular/core'; import { AdminRoutingModule } from './admin-routing.module'; // 其他必要的组件/模块导入 @NgModule({ imports: [AdminRoutingModule], declarations: [LayoutComponent], // 声明Admin模块的组件 // 其他配置项 }) export class AdminModule { static forRoot(configProvider: Provider[]): ModuleWithProviders { return { ngModule: AdminModule, providers: [...configProvider] }; } }
步骤3:在AppModule中导入AdminModule
修改AppRoutingModule,移除对adminRoutes的数组扩展,改为在AppModule中导入AdminModule.forRoot(...):
// AppRoutingModule.ts import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; import { HomeComponent } from './home/home.component'; import { LayoutComponent } from './layout/layout.component'; @NgModule({ imports: [ RouterModule.forRoot([ { path: '', component: LayoutComponent, children: [ {path: '', redirectTo: 'home', pathMatch: 'full'}, {path: 'home', component: HomeComponent} // 移除...adminRoutes ] } ]) ], exports: [RouterModule] }) export class AppRoutingModule { }
// AppModule.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { AdminModule } from '@ui/admin-module'; // 其他导入 @NgModule({ imports: [ BrowserModule, AppRoutingModule, AdminModule.forRoot([]) // 传入你的configProvider配置 ], // 其他配置 }) export class AppModule { }
3. 清理编译缓存
有时候旧的编译缓存会干扰首次构建,执行以下操作清理缓存后再尝试首次编译:
- 删除项目根目录下的
dist文件夹; - 删除
node_modules/.cache文件夹(如果存在); - 执行命令:
ng clean(Angular CLI 6+支持)或npm run clean(如果package.json中有配置)。
验证
完成上述修改后,执行ng build --prod(触发AOT编译)检查首次构建是否还会出现错误,若错误消失,说明问题已解决。
内容的提问来源于stack exchange,提问作者Abhishek

