Tous les articles

·4 min de lecture

Optimizing Angular Build Time with esbuild: Concrete Strategies for 30% Faster Builds

esbuild is 10× faster than Webpack, but misconfigured, it becomes a bottleneck. Learn how to reduce build times by 30–50% in both development and production.

Angular 17+ defaults to esbuild, a major decision that transformed compilation speed. Unlike Webpack, esbuild runs in Go, allowing natural parallelization and avoiding memory overhead. However, switching to esbuild doesn't automatically mean your build is optimal. Angular's default configuration works fine for small projects, but once you exceed 500 components or integrate micro-frontends, slowdowns emerge. The secret isn't to "force" esbuild faster, but to understand where it actually spends its cycles.

Identifying Real Bottlenecks: Beyond Gut Feeling

Too many developers optimize blindly. Before touching anything, activate precise measurement. Angular CLI already gives you insights via ng build --configuration production --stats-json . This command generates a stats.json file analyzable with webpack-bundle-analyzer or source-map-explorer . Yes, it's counterintuitive using Webpack tools to analyze an esbuild build, but these tools read the final bundle, not the build system itself. You'll quickly discover real bloat sources: unused dependencies, un-tree-shaken polyfills, or dead code. One team I advised found 200 KB of unused dependencies in 10 minutes of bundle analysis. Without this measurement, they would have wasted hours optimizing the wrong thing.

Another critical metric: build time per stage. Run ng build --configuration production --verbose to see details. esbuild itself is fast, but Angular performs several steps before and after: AOT compilation, tree-shaking, minification, source map generation. Each can consume time depending on configuration. If AOT compilation takes 40 of 60 seconds, bundling optimization helps only marginally. It's an analysis problem, not a bundler problem.

Configuring esbuild for Parallelism and Memory

By default, Angular doesn't explicitly configure esbuild to maximize parallelism. You can do this via angular.json . The key is esbuildOptions in the build configuration. Here's a concrete approach:

"build": {
  "options": {
    "esbuildOptions": {
      "define": {
        "ngDevMode": false,
        "ngI18nClosureMode": false
      },
      "logLevel": "warning",
      "splitting": true,
      "minify": true,
      "sourcemap": false,
      "target": ["ES2022"]
    }
  },
  "configurations": {
    "production": {
      "budgets": [{"type": "bundle", "maximumWarning": "500kb", "maximumError": "1mb"}],
      "sourceMap": false,
      "outputHashing": "all"
    }
  }
}

The splitting directive is essential: it forces esbuild to create multiple chunks instead of a single bundle, improving parallelism and allowing the browser to load code more efficiently. logLevel: warning reduces log noise, also speeding output. Removing sourcemap in production is obvious, but many do it in development too, losing a debugging resource. Instead, use inline or deported source maps on a separate CDN.

Lazy Loading and Code Splitting: The Art of Loading Only What You Need

esbuild excels when given distinct chunks to compile. The problem: many Angular projects load everything at startup. Verify your routing: every route except the root module should be lazy-loaded. It's basic, but I've seen 50-component apps loading 95% of code on startup. Here's the correct pattern:

const routes: Routes = [
  { path: '', component: HomeComponent },
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
    canActivate: [AuthGuard]
  },
  {
    path: 'dashboard',
    loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule)
  }
];

Beyond routing, Angular 14+ supports lazy-loaded component without modules. This reduces verbosity and improves isolation. Each lazy-loaded chunk is compiled independently by esbuild, meaning if you modify the admin module, only that chunk rebuilds in development. On a 100 KB business code app split across 8 modules, this drops from 8-second rebuilds to 2 seconds.

External Dependencies and `node_modules`: The Silent Trap

esbuild bundles everything, including node_modules , which is correct for production but catastrophic in development. Every npm install or dependency upgrade forces a full bundle rebuild because esbuild must re-parse all files. The solution: configure externalDependencies for certain libraries. However, beware: this only works if you serve those dependencies via CDN or separate loader. For most apps, it's impractical. Instead, minimize dependencies. One team reduced 40 dependencies to 15 using native APIs (Fetch instead of Axios, RxJS instead of lodash, etc.). Build time dropped from 45 to 18 seconds, and the final bundle lost 120 KB.

Inspect your package.json with npm ls to detect duplicate or conflicting dependencies. esbuild must resolve them on every build. A simple npm dedupe can save seconds.

Common Pitfalls: What Actually Slows You Down

Many developers enable sourceMap: true everywhere, even in production. Source maps can double build time and triple bundle size. Use them in development only, preferring eval-source-maps which are faster. Another pitfall: too many polyfills . Angular includes IE11 polyfills by default in older versions. If you support ES2020+, remove them. Finally, lazy-loaded modules that aren't truly lazy because they're imported in the root module. Check your imports: if you write import { AdminComponent } from './admin/admin.component' instead of dynamic import, you break lazy-loading.

A classic mistake: manually configuring optimization thinking you're improving esbuild. esbuild already handles minification, tree-shaking, and deduplication. Adding extra Webpack options only creates confusion.

Conclusion: Measure, Target, Validate

Optimizing Angular build time with esbuild starts by understanding where time flows. Enable --stats-json , measure each stage, then apply changes in order: 1) Lazy-load aggressively, 2) Prune dependencies, 3) Configure esbuild for parallelism, 4) Fine-tune source maps and polyfills. Don't aim for 0 seconds, aim for 20–30 seconds in production and 5 seconds in development. It's realistic and impactful. Measure before and after each change with time ng build to avoid premature optimization. The effort pays off: a 10-dev team saving 30 seconds per build saves 50 hours monthly.