Webpack / Rollup Bundle Stats Visualizer

Visualize a webpack stats.json or rollup bundle as a treemap

Free webpack and rollup bundle analyzer — paste a stats.json or bundle report and see module sizes as an interactive squarified treemap, coloured by chunk. Spot large dependencies instantly. Runs in your browser; no bundle data uploaded. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

How do I produce a webpack stats.json?

Run webpack with the stats flag, for example `webpack --profile --json > stats.json`, or set `stats: 'normal'` and write the JSON in your config. The file contains a modules array with each module's name, size, and chunk membership, which is what this tool reads.

A bundle stats visualizer turns a webpack or rollup build report into a treemap so you can see at a glance which modules dominate your JavaScript bundle. Large dependencies are the most common cause of slow page loads, and a flat list of sizes is hard to scan. This tool renders module sizes as proportional rectangles, coloured by chunk, entirely in your browser.

How it works

The visualizer first parses your JSON and auto-detects its shape. A webpack stats.json exposes a modules array where each entry has a name, a size in bytes, and a list of chunks; the tool maps chunk IDs to their human names. A rollup-plugin-visualizer export is a tree of nodes carrying value or renderedLength sizes and children, which the tool walks down to the leaves. A plain object mapping module paths to byte counts is also accepted.

Once it has a flat list of modules with sizes, it builds the layout using the squarified treemap algorithm of Bruls, Huizing, and van Wijk. The algorithm fills the canvas row by row, choosing whether to add the next module to the current row based on which option keeps the rectangles closest to square — the “worst aspect ratio” heuristic. The result is a tiling where every tile’s area is exactly proportional to its module’s size and the whole area sums to the canvas.

How to generate the input file

Webpack:

webpack --profile --json > stats.json

Or from your webpack.config.js:

module.exports = {
  stats: {
    modules: true,
    entrypoints: true,
    chunkModules: true,
  },
};

Run the build and capture the stdout output as stats.json. The file can be large (several megabytes for a complex app), which is expected.

Rollup with rollup-plugin-visualizer:

import { visualizer } from "rollup-plugin-visualizer";

export default {
  plugins: [
    visualizer({ template: "treemap", filename: "stats.json", open: false }),
  ],
};

After building, stats.json in your project root contains the tree structure this tool accepts.

Reading the treemap

Tile size = module size. The area of each rectangle is directly proportional to that module’s byte count in the bundle. A tile that covers 20% of the canvas means that module is 20% of the total bundle size.

Colour = chunk. Different chunks (main, vendor, lazy routes) are shown in different colours so you can immediately see which chunk is heaviest. Common findings:

  • A vendor chunk dominated by a handful of large packages (moment.js, lodash, chart libraries).
  • Route-level chunks that are unexpectedly large because a dependency was not properly lazy-loaded.
  • Duplicate modules appearing in multiple chunks because shared code was not extracted into a common chunk.

Hover for exact figures. The tooltip shows the module’s path, its size in bytes and as a percentage of the total, and which chunk it belongs to.

What to do with the results

Once you identify the largest tiles, the typical optimisation paths are:

  • Replace heavy libraries. If moment.js dominates, consider date-fns or dayjs, which are a fraction of the size for most use cases.
  • Tree-shake properly. If you see individual lodash methods imported (for example, lodash/cloneDeep) but the whole lodash bundle is still present, check your import style — import { cloneDeep } from 'lodash' imports the entire library; import cloneDeep from 'lodash/cloneDeep' does not.
  • Lazy-load routes. If page-specific components appear in the main bundle, move them behind import() dynamic imports so they only load when needed.
  • Deduplicate. If the same dependency appears in both the main chunk and a lazy chunk, configure splitChunks (webpack) or manualChunks (Rollup) to extract the shared module into its own chunk.

Everything runs locally, so private builds stay on your machine.