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 serve but not with ng build --prod
  • Network tab shows 404 for chunk JavaScript files
  • Error appears after deploying to a subdirectory

Real Error Message

bash
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

typescript
// 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

json
// 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

json
// 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 {} ```