在 Angular 项目开发中,随着业务功能的不断迭代,代码体积会持续膨胀,直接导致应用首屏加载时间过长、用户体验下降。而路由懒加载(Lazy Loading)作为 Angular 内置的性能优化核心方案,通过loadChildren实现模块按需加载,能大幅削减首屏加载的代码体积,是中大型 Angular 应用必用的优化手段。本文将从原理、实现、最佳实践三个维度,带你彻底掌握 Angular 路由懒加载的落地方法。
一、路由懒加载核心原理
Angular 默认的模块加载方式是预加载:应用启动时会一次性加载所有模块的代码(打包到同一个 chunk 文件中),即使某些模块(如个人中心、设置页)用户暂时不会访问。
而懒加载的核心逻辑是:将应用按路由拆分为多个独立模块,仅在用户访问对应路由时,才通过loadChildren动态加载该模块的代码包(生成独立的 chunk 文件)。简单来说,就是 “用的时候再加载”,从根源上减少首屏需要加载的资源体积。
关键概念:loadChildren
loadChildren是 Angular 路由配置中的核心属性,用于指定懒加载模块的加载路径和导出类,其底层基于 ES6 的动态导入(import())实现,返回一个 Promise,Angular 会在路由激活时执行这个 Promise 并加载对应模块。
二、从零实现 Angular 路由懒加载
1. 环境准备
确保你的项目基于 Angular 8+(不同版本loadChildren语法略有差异,本文以 Angular 16 为例),先创建一个基础 Angular 项目:
# 新建项目 ng new angular-lazy-load-demo # 进入项目目录 cd angular-lazy-load-demo2. 创建懒加载模块
以 “用户模块(UserModule)” 和 “商品模块(ProductModule)” 为例,创建带路由的懒加载模块:
# 创建用户模块(含路由模块) ng generate module user --routing # 创建用户模块下的组件 ng generate component user/profile ng generate component user/settings # 创建商品模块(含路由模块) ng generate module product --routing # 创建商品模块下的组件 ng generate component product/list ng generate component product/detail3. 配置懒加载模块的子路由
首先配置子模块的路由(以user-routing.module.ts为例):
// src/app/user/user-routing.module.ts import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { ProfileComponent } from './profile/profile.component'; import { SettingsComponent } from './settings/settings.component'; // 子路由配置 const routes: Routes = [ { path: '', redirectTo: 'profile', pathMatch: 'full' }, // 默认跳转到个人中心 { path: 'profile', component: ProfileComponent }, { path: 'settings', component: SettingsComponent } ]; @NgModule({ imports: [RouterModule.forChild(routes)], // 子模块用forChild exports: [RouterModule] }) export class UserRoutingModule { }同理配置product-routing.module.ts,核心是使用RouterModule.forChild()定义子路由(根路由用forRoot())。
4. 根路由配置 loadChildren 实现懒加载
修改根路由模块app-routing.module.ts,通过loadChildren指定懒加载模块的路径:
// src/app/app-routing.module.ts import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { HomeComponent } from './home/home.component'; // 首屏首页组件 const routes: Routes = [ { path: '', component: HomeComponent }, // 首屏加载首页 // 懒加载用户模块:路径匹配user/**时,加载UserModule { path: 'user', loadChildren: () => import('./user/user.module').then(m => m.UserModule) }, // 懒加载商品模块:路径匹配product/**时,加载ProductModule { path: 'product', loadChildren: () => import('./product/product.module').then(m => m.ProductModule) }, { path: '**', redirectTo: '' } // 404重定向 ]; @NgModule({ imports: [RouterModule.forRoot(routes)], // 根路由用forRoot exports: [RouterModule] }) export class AppRoutingModule { }语法说明
Angular 8 + 推荐使用动态导入的箭头函数语法:
loadChildren: () => import('模块路径').then(m => m.模块类名)旧版本(Angular 7 及以下)的字符串语法已被废弃,不建议使用:
// 废弃语法,仅作了解 loadChildren: './user/user.module#UserModule'5. 验证懒加载效果
启动项目并访问:
ng serve --open打开浏览器开发者工具(F12),切换到「Network」面板:
- 首次加载页面时,仅会加载根模块的 chunk 文件(如
main.js、polyfills.js),不会加载user和product模块的代码; - 当点击跳转到
/user/profile时,会新增加载user-module.js(用户模块的 chunk 文件); - 当点击跳转到
/product/list时,会新增加载product-module.js(商品模块的 chunk 文件)。
这就证明懒加载已经生效!
三、懒加载进阶优化
1. 预加载策略:平衡加载时机
懒加载虽优化了首屏,但首次访问懒加载路由时可能出现短暂等待。Angular 提供预加载策略,可在首屏加载完成后,空闲时提前加载部分核心懒加载模块:
// src/app/app-routing.module.ts import { NgModule } from '@angular/core'; import { RouterModule, Routes, PreloadAllModules } from '@angular/router'; const routes: Routes = [/* 原有路由配置 */]; @NgModule({ imports: [ RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules // 预加载所有懒加载模块 }) ], exports: [RouterModule] }) export class AppRoutingModule { }也可自定义预加载策略(如仅预加载指定模块),满足更精细的性能需求。
2. 错误处理:加载失败兜底
当懒加载模块加载失败(如网络异常),可通过路由守卫或错误处理器兜底:
// 自定义懒加载错误处理 const routes: Routes = [ { path: 'user', loadChildren: () => import('./user/user.module') .then(m => m.UserModule) .catch(() => import('./error/error.module').then(m => m.ErrorModule)) // 加载失败跳错误模块 } ];3. 模块拆分原则
- 按业务域拆分:如用户、商品、订单各为一个懒加载模块;
- 避免过小模块:单个模块代码体积建议不小于 100KB,否则 chunk 文件过多反而增加请求开销;
- 公共模块抽离:将多个懒加载模块共用的组件 / 服务抽离到
SharedModule,避免重复打包。
四、常见问题排查
- 懒加载模块无法路由:检查子模块是否导入
RouterModule.forChild(),且根路由path与子路由path是否匹配; - 重复加载模块:确保懒加载模块未被根模块
AppModule导入(根模块导入会导致预加载); - chunk 文件命名不清晰:可在
angular.json中配置 outputHashing,自定义 chunk 文件名:"build": { "options": { "outputHashing": "all", "chunkIds": "named" } }
总结
- Angular 路由懒加载通过
loadChildren结合动态导入import()实现模块按需加载,核心是减少首屏加载的代码体积; - 实现懒加载需遵循 “根路由配置 loadChildren + 子模块配置 forChild 路由 + 避免根模块导入懒加载模块” 三大核心步骤;
- 可通过预加载策略、错误兜底、合理拆分模块进一步优化懒加载效果,平衡首屏性能和路由访问体验。
路由懒加载是 Angular 中大型应用性能优化的 “标配”,掌握这一技术能显著提升应用的加载速度和用户体验,也是 Angular 开发者进阶的必备技能。