Introduction
Angular's lazy loading splits the application into chunks that are loaded on demand. In production builds, lazy loaded modules may fail to load with errors like:
ERROR Error: Uncaught (in promise): Error: Cannot find module './features/admin/admin.module'
ChunkLoadError: Loading chunk 5 failed.
(error: https://example.com/5.abc123.js)This typically happens due to route configuration issues, deployment path mismatches, or build optimization problems.
Symptoms
- Lazy loaded routes work in development (
ng serve) but fail in production - Browser console shows "Cannot find module" or "ChunkLoadError"
- Network tab shows 404 for chunk files (e.g.,
5.abc123.js) - Application works after hard refresh but fails on navigation
- Error occurs after deploying to a subdirectory or different base href
Common Causes
- Incorrect
loadChildrenpath syntax in route configuration base-hrefmismatch between build configuration and deployment path- Deployment does not include all generated chunk files
- Service Worker caches old chunk references after a new deployment
- Build optimization removes code that is dynamically imported
Step-by-Step Fix
- 1.Use the correct loadChildren syntax for your Angular version:
- 2.```typescript
- 3.// Angular 8+ (recommended)
- 4.const routes: Routes = [
- 5.{
- 6.path: 'admin',
- 7.loadChildren: () => import('./features/admin/admin.module')
- 8..then(m => m.AdminModule),
- 9.},
- 10.];
// BAD: string-based syntax (deprecated in Angular 8+) // loadChildren: './features/admin/admin.module#AdminModule' ```
- 1.Set the correct base-href in your build command:
- 2.```bash
- 3.# If deploying to https://example.com/myapp/
- 4.ng build --base-href=/myapp/
# Or configure in angular.json ```
- 1.Verify all chunk files are deployed. After building, check the
dist/output: - 2.```bash
- 3.ls -la dist/myapp/*.js | grep -E "[0-9]+\.[a-f0-9]+\.js"
- 4.
` - 5.Ensure all chunk files are uploaded to your server/CDN.
- 6.Handle chunk load errors with a global error handler:
- 7.```typescript
- 8.// app.module.ts
- 9.import { ErrorHandler } from '@angular/core';
- 10.import { Router } from '@angular/router';
export class GlobalErrorHandler implements ErrorHandler { constructor(private router: Router) {}
handleError(error: any) { if (error.message && error.message.includes('Loading chunk')) { // New version deployed, reload the page window.location.reload(); return; } console.error('An error occurred:', error); } }
@NgModule({ providers: [{ provide: ErrorHandler, useClass: GlobalErrorHandler }], }) export class AppModule {} ```
- 1.Configure the Service Worker to handle updates properly:
- 2.```json
- 3.// ngsw-config.json
- 4.{
- 5."index": "/index.html",
- 6."assetGroups": [{
- 7."installMode": "prefetch",
- 8."updateMode": "prefetch",
- 9."resources": {
- 10."files": ["/favicon.ico", "/index.html", "/*.css", "/*.js"]
- 11.}
- 12.}]
- 13.}
- 14.
`
Prevention
- Always use dynamic
import()syntax for lazy loaded modules - Include chunk load error handling in every Angular application
- Test lazy loaded routes in production mode locally:
ng build && npx http-server dist/myapp - Verify all build artifacts are deployed, not just the main bundle
- Monitor chunk 404 rates in production to detect deployment issues
- Use the Angular Service Worker's
SwUpdateservice to detect and apply updates - Add lazy loading route tests to your E2E test suite to verify all routes load correctly