Bundle analysis là bước đầu tiên khi optimize bundle size — không phỏng đoán, phải đo.
- Tools: webpack-bundle-analyzer (treemap visualization), vite-bundle-visualizer (rollup-plugin-visualizer), source-map-explorer (analyze actual bundle không phải estimates), bundlephobia.com (check package size trước khi install).
- Những gì cần tìm: Large dependencies có alternatives nhỏ hơn — moment.js (330KB) → date-fns/dayjs (10KB); lodash (71KB full) → lodash-es + tree shaking hoặc chỉ import specific: import debounce from 'lodash/debounce'; chart.js (200KB) → recharts (160KB) → victory (100KB).
- Duplicate modules: cùng dependency nhiều versions (webpack deduplication), cùng code ở nhiều chunks.
- Unexpected large modules: ví dụ icon library import toàn bộ thay vì specific icons — @mui/icons-material 30MB vs import MenuIcon from '@mui/icons-material/Menu' (một file).
- Giải pháp: Tree shaking (sideEffects: false trong package.json), code splitting + dynamic imports, externals (load React từ CDN thay vì bundle), Module Federation (share dependencies giữa micro-frontends).
- Compression context: gzip/Brotli reduce bundle size 60-80% — báo cáo compressed size thực tế, không raw.
- Benchmark: track bundle size trong CI với size-limit package — fail build nếu bundle vượt threshold.
Bundle analysis is the first step when optimizing bundle size — measure, don't guess.
- Tools: webpack-bundle-analyzer (treemap visualization), vite-bundle-visualizer (rollup-plugin-visualizer), source-map-explorer (analyzes the actual bundle, not estimates), bundlephobia.com (check package size before installing).
- What to look for: Large dependencies with smaller alternatives — moment.js (330KB) → date-fns/dayjs (10KB); lodash (71KB full) → lodash-es + tree shaking or specific imports: import debounce from 'lodash/debounce'; chart.js (200KB) → recharts (160KB) → victory (100KB).
- Duplicate modules: same dependency at multiple versions (webpack deduplication), same code in multiple chunks.
- Unexpectedly large modules: for example, an icon library imported in full instead of specific icons — @mui/icons-material 30MB vs import MenuIcon from '@mui/icons-material/Menu' (a single file).
- Solutions: tree shaking (sideEffects: false in package.json), code splitting + dynamic imports, externals (load React from CDN instead of bundling), Module Federation (share dependencies between micro-frontends).
- Compression context: gzip/Brotli reduce bundle size by 60-80% — report compressed sizes, not raw.
- Benchmark: track bundle size in CI with the size-limit package — fail the build if the bundle exceeds a threshold.