Angular CLI:从Node Modules导入模块配置loadChildren懒加载异常
我来帮你排查这个Angular懒加载自定义npm模块的问题,咱们一步步来梳理和解决:
我希望从node modules中导入自定义模块,该模块包含需要导航的路由。具体目标是:
- 在
app.module中配置从node modules内的模块通过loadChildren实现懒加载 - 为
TestModule配置forRoot以实现其路由的懒加载 TestModule是通过Angular CLI 6内置的ng-packagr打包生成的dist文件夹,并已添加到node modules中
现有核心代码
核心应用模块(app.module.ts)
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; import { AppComponent } from './app.component'; import { TestModule } from "test"; @NgModule({ declarations: [ AppComponent ], imports: [ TestModule, BrowserModule, RouterModule.forRoot( [ { path: "", redirectTo: "test", pathMatch: "full" }, { path: "test", loadChildren: "test#TestModule" }, ]) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
自定义npm包(TestModule)
import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; import { HomeComponent } from './containers/home/home.component'; import { LayoutSidebarComponent } from './layouts/layout-sidebar/layout-sidebar.component'; const COMPONENTS = [ HomeComponent ]; @NgModule({ imports: [ CommonModule, RouterModule.forChild([ { path: '', pathMatch: 'full', component: LayoutSidebarComponent, children: [ { path: '', component: HomeComponent } ] } ]) ], declarations: [...COMPONENTS], exports: [] }) export class TestModule {}
tsconfig.app.json
{ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/app", "module": "es2015", "types": [ "node" ] }, "include": [ "../node_modules/test/**/*.ts" ], "exclude": [ "src/test.ts", "**/*.spec.ts" ] }
当前问题
执行ng serve启动localhost:4200时,控制台及命令行均无报错,但核心应用模块似乎未加载,无报错信息导致调试困难。当前环境:Angular CLI 6、Angular 6、ng-packagr、webpack及iTerm。
咱们先拆解现有代码里的几个关键问题,再逐一修复:
1. 根模块同时导入+懒加载,导致模块提前加载
你在AppModule的imports里直接导入了TestModule,这会让模块被立即加载,完全抵消了懒加载的作用。首先要把这行导入移除,只保留loadChildren的懒加载配置。
2. TestModule缺少forRoot方法(规范+避免重复配置)
虽然懒加载时路由会单独处理,但Angular模块的最佳实践是为可复用模块提供forRoot静态方法,用来导出根级配置(比如全局服务、路由),避免重复初始化。
3. 懒加载语法过时(Angular 6推荐动态导入)
Angular 6开始推荐使用动态导入语法替代旧的"test#TestModule"写法,这样webpack能更精准地做代码分割。
4. tsconfig包含node_modules的TS文件多余且可能冲突
node_modules里的模块已经是编译好的产物,不需要把它的TS文件纳入你的应用编译流程,反而可能导致编译异常。
步骤1:修改AppModule,移除直接导入+更新懒加载语法
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; import { AppComponent } from './app.component'; // 移除这行直接导入:import { TestModule } from "test"; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, RouterModule.forRoot( [ { path: "", redirectTo: "test", pathMatch: "full" }, // 更新为Angular 6推荐的动态导入语法 { path: "test", loadChildren: () => import('test').then(m => m.TestModule) }, ]) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
步骤2:为TestModule添加forRoot方法+修复组件声明
注意:原来的代码里LayoutSidebarComponent没加入declarations数组,这会导致组件找不到的隐性错误,一定要补上!
import { CommonModule } from '@angular/common'; import { NgModule, ModuleWithProviders } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { HomeComponent } from './containers/home/home.component'; import { LayoutSidebarComponent } from './layouts/layout-sidebar/layout-sidebar.component'; // 补上LayoutSidebarComponent const COMPONENTS = [ HomeComponent, LayoutSidebarComponent ]; const routes: Routes = [ { path: '', component: LayoutSidebarComponent, children: [ { path: '', component: HomeComponent } ] } ]; @NgModule({ imports: [ CommonModule, RouterModule.forChild(routes) ], declarations: [...COMPONENTS], exports: [] }) export class TestModule { // 添加forRoot静态方法,符合Angular模块规范 static forRoot(): ModuleWithProviders<TestModule> { return { ngModule: TestModule, providers: [] // 如果有全局服务,可以在这里注册 }; } // 可选:添加日志验证模块加载 constructor() { console.log('TestModule 已懒加载!'); } }
步骤3:修改tsconfig.app.json,移除多余的include配置
{ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/app", "module": "es2015", "types": [ "node" ] }, "exclude": [ "src/test.ts", "**/*.spec.ts" ] }
步骤4:重新打包TestModule并更新依赖
在TestModule的项目目录下重新打包:
ng build --prod
然后在核心应用中更新依赖:
- 如果是本地链接的模块:执行
npm link test - 如果是发布到npm的模块:执行
npm install test
步骤5:验证懒加载效果
启动应用:
ng serve
打开浏览器开发者工具的Network标签,访问localhost:4200,当跳转到/test路径时,你会看到一个新的chunk文件(比如test-xxx.js)被加载,同时控制台会打印TestModule 已懒加载!的日志,说明懒加载成功生效。
内容的提问来源于stack exchange,提问作者AngularM

