- initial: main bundle — warning 500 kB, error 1 MB.
- anyComponentStyle: per-component CSS — warning 2 kB, error 4 kB.
- anyScript: each lazy route chunk — warning 250 kB, error 400 kB.
Build fails if any budget is exceeded.
- Install deps (includes
source-map-explorer), then run:npm run analyze
- Open
bundle-stats.htmlin the project root (generated by the command above). The file is in.gitignore. - In the report, look at the largest blocks (Angular, RxJS, NgRx, Tailwind, your app). Use that to decide what to lazy-load or trim.
Manual steps: npm run build:analyze then npx source-map-explorer dist/shopFlow/browser/*.js --html bundle-stats.html.
- Run
npm run analyzeand openbundle-stats.htmlin the browser. - Focus on the initial chunks (main, polyfills, first few chunk-*.js). The biggest blocks are usually Angular, RxJS, NgRx, zone.js, Tailwind.
- Lazy load features: Auth, product, cart, checkout, user routes are already lazy. Avoid importing heavy feature code from
app.config.tsorapp.routes.ts; useloadChildren/loadComponentso code lives in lazy chunks. - Heavy libs in lazy routes: ngx-stripe is already loaded only with the checkout module. Add any other heavy libs (charts, rich editors, etc.) only inside lazy-loaded modules.
- RxJS: Use named imports (
import { map, of } from 'rxjs'), notimport * as rxjsor full paths that pull in the whole library.
- Store DevTools: Already only in dev (
!environment.production). Production build does not include it. - Route config: If you import route arrays from feature modules in
app.routes.ts(e.g.productRoutes,cartRoutes), their module code can be pulled into main. To move more to lazy chunks, you can switch those toloadChildrenthat import the route config (e.g.loadChildren: () => import('./modules/product-module/product.routes').then(m => m.productRoutes)and export the routes from the module). - Tree-shaking: Avoid barrel re-exports that pull in unused code (e.g.
export * from './many-files'). Prefer direct imports where it makes sense.
- Tailwind: Purge is already on —
tailwind.config.jshascontent: ["./src/**/*.{html,ts}"], so only classes that appear in the app are in the final CSS (~45 kB). Nothing to change there unless you want to go further:- Optional — fewer base styles: The full
@import 'tailwindcss'includes Preflight (Tailwind’s base reset). If you don’t need it, you can import only theme + utilities (Tailwind v4) and add your own base (e.g.box-sizing, minimal reset) instyles.css. That can save a few kB but may affect layout; test after switching. - Optional — fewer utilities: Prefer a small set of spacing/color classes (e.g. one gray scale, one or two spacing scales) instead of many one-off values; that doesn’t reduce size much with purge but keeps the design consistent and the source easier to maintain.
- Optional — fewer base styles: The full
- Icons: SVG components in
src/assets/icons/are in the JS bundle. If the set grows large, consider a sprite or lazy-loaded icon set. - Images: Use
loading="lazy"and fixed dimensions where possible to avoid layout shift; optimize assets (WebP, compression).
- If you’re only slightly over the warning (e.g. 501 kB vs 500 kB), you can raise the warning in
angular.json(e.g. to 520 kB) so CI stays green while you work on reductions. - For real reductions, use the report to remove or lazy-load the largest dependencies in the initial chunks.
- Don’t import heavy modules in the root app: e.g.
ReactiveFormsModule/FormsModuleonly in components that use forms (saves ~40 kB if removed from root). - Icons: SVG components under
src/assets/icons/are in the JS bundle. Prefer direct imports (e.g.from 'assets/icons/cart') instead of the barrel (from 'assets/icons') so only the icon you use is bundled in that chunk. The barrel pulls in all icons and can add ~5 kB or more to initial or lazy chunks. - Barrel imports: In hot path (app.config, app.routes, root component) prefer direct imports; in lazy modules, barrels are less critical but can still pull extra code.
- NgRx: Auth store and effects are in the main bundle by design. To shrink further you’d need a lighter auth solution (e.g. service + signals), which is a larger refactor.
- Zoneless (experimental): Angular’s zoneless option can reduce bundle size by not loading zone.js; it requires compatibility checks and testing.
Already done: lazy route configs (loadChildren), no ReactiveFormsModule in root, direct icon imports, StoreDevtools only in dev.
| Option | Impact | Effort | Notes |
|---|---|---|---|
Run npm run analyze |
— | Low | Open bundle-stats.html, see exact chunks; decide next cut from the largest blocks. |
| NgRx → lighter auth | High (~20–40 kB) | High | Replace auth store/effects with a service + signals; removes @ngrx/store and @ngrx/effects from initial. |
| Zoneless | Medium (polyfills) | Medium | Use zoneless; test all async, forms, animations. |
| Disable SSR | Server bundle only | Low | If you don't need SSR, set ssr: false in the build config; doesn't change initial browser bundle. |
| Tailwind: no Preflight | Low (few kB) | Low | In styles.css, import only theme + utilities (see comment there); add your own base (e.g. box-sizing). |
| npm dedupe / deps:check | Low | Low | Fewer duplicate deps can slightly reduce build output. |
| Fewer design tokens | Low | Medium | In Tailwind, use a smaller palette/spacing scale so fewer utility variants are generated. |
Beyond that, the remaining size is mostly Angular core, RxJS, router, and zone — hard to reduce without changing framework or going zoneless.
- Run
npm run deps:checkto list the dependency tree. - Run
npm dedupeto reduce duplicates when possible. - If a lazy chunk is too big, check for accidental duplicate or heavy libs and prefer lazy loading or lighter alternatives.
- Icons: under
src/assets/icons/are TS/SVG components (in the JS bundle). - Images: e.g.
src/assets/products/image.png— keep optimized (e.g. compressed PNG/WebP, reasonable dimensions). Add more undersrc/assetsas needed; they are copied as-is. Use responsive images and lazy loading in templates where it helps.
Run before merge / in CI:
npm run lintnpm run build:prod(fails if budgets are exceeded)
This keeps the initial bundle within budgets with headroom and avoids unexpectedly large lazy chunks.