Bundle Analyzer
Open up the bundle as a treemap, find the modules eating your budget, and decide what to cut or split.
Tree shaking and splitting only help if you know what's actually in your bundle. A bundle analyzer turns the build into a picture — a treemap where every box is a module sized by its weight — so the bloat you never suspected becomes impossible to miss. This is how a 142 KB bundle becomes 61 KB without removing a single feature.
Seeing inside the build
Your bundler already emits a stats file describing every module it included and how big each is. A bundle analyzer reads that and draws an interactive treemap. Because the step is bundler-specific, each has its own: webpack-bundle-analyzer, Vite's rollup-plugin-visualizer, and so on — same idea everywhere.
It exists to answer the questions you ask during a performance audit:
- Why is this bundle 2 MB — what's actually in it?
- How big is my code vs. the third-party deps?
- Did tree shaking work, or did a whole library sneak in?
- Is a dependency duplicated across chunks?
Explore a real bundle
Here's a tiny To-Do app that imported moment (for a date) and lodash (for one sum). The treemap shows the truth: your code is a sliver, and the dependencies dwarf it. Click boxes to inspect them, then hit Apply fixes and watch the bloat collapse:
Stat vs parsed vs gzipped
Analyzers report three sizes, and confusing them leads to wrong conclusions:
- Stat — raw source size, before minification. Biggest, least meaningful.
- Parsed — after minification; what the browser actually parses & executes.
- Gzipped — after compression; the real download cost over the wire.
The two classic culprits
moment.js shipping every locale
moment bundles all its language locales by default — often more weight than the library itself, for translations you'll never use. Strip them (or switch to a lighter date lib):
const webpack = require("webpack");
plugins: [
// Don't bundle any moment locale files
new webpack.IgnorePlugin({ resourceRegExp: /./locale$/, contextRegExp: /moment$/ }),
];lodash imported whole
Plain lodash isn't tree-shakable, so import _ from "lodash" drags in everything for one function. Import the single function, or use the ESM build:
// ❌ pulls in all of lodash (~24 KB gzipped)
import _ from "lodash";
_.sum(nums);
// ✓ just the one function (~0.2 KB)
import sum from "lodash/sum";
// …or the tree-shakable ESM build:
import { sum } from "lodash-es";- →A bundle analyzer visualizes the build as a treemap — box size = module weight.
- →It answers the audit questions: why is it big, my code vs deps, did tree-shaking work, anything duplicated.
- →Read gzipped for download cost, parsed for parse/CPU cost.
- →Classic culprits: moment locales and whole-lodash imports.
- →Targeted fixes from one look can halve a bundle with zero feature loss.