The Problem
Lazy loaded modules work perfectly in development but fail in production builds. The browser cannot load the chunk files, resulting in blank pages or navigation errors.
Symptoms
- Navigation to lazy-loaded route shows blank page
- Console error: "Loading chunk X failed"
- Works with
ng servebut not withng build --prod - Network tab shows 404 for chunk JavaScript files
- Error appears after deploying to a subdirectory
Real Error Message
ERROR Error: Uncaught (in promise): ChunkLoadError: Loading chunk
src_app_modules_admin_admin_module_ts failed.
(error: https://example.com/src_app_modules_admin_admin_module_ts.js)Common Causes
Cause 1: Deploy URL Mismatch
// app-routing.module.ts
const routes: Routes = [
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
}
];When deployed to a subdirectory (e.g., https://example.com/my-app/), the chunk files are requested from the root instead of the subdirectory.
Cause 2: Build Configuration Missing Public Path
// angular.json (WRONG)
{
"projects": {
"my-app": {
"architect": {
"build": {
"options": {
"outputPath": "dist/my-app"
// Missing deployUrl or baseHref
}
}
}
}
}
}How to Fix It
Fix 1: Set Correct base-href
```bash # Build with correct base href ng build --base-href=/my-app/
# Or in angular.json "options": { "baseHref": "/my-app/" } ```
Fix 2: Use runtime configuration for lazy loading
```typescript // Set public path at runtime based on deployment declare const __webpack_public_path__: string;
if (window.__webpackPublicPath__) { __webpack_public_path__ = window.__webpackPublicPath__; }
// Then lazy load normally { path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule) } ```
Fix 3: Configure chunkHash for Cache Busting
// angular.json
{
"configurations": {
"production": {
"outputHashing": "all",
"namedChunks": false,
"extractLicenses": true
}
}
}Fix 4: Add Error Handling for Chunk Load Failures
```typescript // app-routing.module.ts import { Route, Router } from '@angular/router';
const routes: Routes = [ { path: 'admin', loadChildren: () => import('./admin/admin.module') .then(m => m.AdminModule) .catch(() => { window.location.reload(); // Retry on chunk load failure return { AdminModule: null } as any; }) } ]; ```
Fix 5: Preload Critical Lazy Modules
```typescript import { PreloadAllModules, RouterModule } from '@angular/router';
@NgModule({ imports: [ RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }) ] }) export class AppRoutingModule {} ```