documentation

Supported Formats

Webpack stats, esbuild metafile, source-map-explorer, and rollup-stats JSON

dendrobundle auto-detects the format by inspecting the top-level structure of the JSON you POST. No format flag needed.

webpack-stats

Generated by running webpack with --json:

npx webpack --profile --json > dist/webpack-stats.json

Or via webpack-bundle-analyzer with generateStatsFile: true:

// webpack.config.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerMode: 'disabled',
      generateStatsFile: true,
      statsFilename: 'webpack-stats.json',
    }),
  ],
};

Fields used:

Field Purpose
assets[].name Asset file name
assets[].size Asset size in bytes
assets[].chunkNames Which named chunks the asset belongs to
chunks[].initial Whether this is an initial (non-lazy) chunk
chunks[].files Asset file names this chunk maps to
modules[].name Source module path
modules[].size Rendered size in bytes after tree-shaking

Minimal example:

{
  "assets": [
    { "name": "main.js", "size": 412680, "chunkNames": ["main"] },
    { "name": "vendor.js", "size": 1154020, "chunkNames": ["vendor"] }
  ],
  "chunks": [
    { "id": 0, "names": ["main"], "initial": true, "files": ["main.js"] },
    { "id": 1, "names": ["vendor"], "initial": true, "files": ["vendor.js"] }
  ],
  "modules": [
    { "name": "src/app/app.ts", "size": 4812, "chunkNames": ["main"] },
    { "name": "node_modules/react/index.js", "size": 7240, "chunkNames": ["vendor"] }
  ]
}

esbuild-metafile

Generated with the --metafile CLI flag:

npx esbuild src/index.ts --bundle --metafile=dist/meta.json --outfile=dist/bundle.js

Or via the JavaScript API:

import * as esbuild from 'esbuild';

const result = await esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  outfile: 'dist/bundle.js',
  metafile: true,
});

require('fs').writeFileSync('dist/meta.json', JSON.stringify(result.metafile));

Fields used:

Field Purpose
outputs[key].bytes Total output file size
outputs[key].inputs Map of input file → bytes contributed
outputs[key].entryPoint Entry point that produced this output

Minimal example:

{
  "inputs": {},
  "outputs": {
    "dist/bundle.js": {
      "bytes": 412680,
      "entryPoint": "src/index.ts",
      "inputs": {
        "src/index.ts": { "bytesInOutput": 4812 },
        "src/app/router.ts": { "bytesInOutput": 2140 },
        "node_modules/react/index.js": { "bytesInOutput": 7240 }
      }
    },
    "dist/vendor.js": {
      "bytes": 1154020,
      "inputs": {
        "node_modules/react-dom/index.js": { "bytesInOutput": 580000 }
      }
    }
  }
}

source-map-explorer

Generated by running source-map-explorer with --json:

# Build with source maps first
npm run build -- --sourcemap

# Then extract module breakdown
npx source-map-explorer --json 'dist/*.js' > dist/sme.json

Fields used:

Field Purpose
results[].bundleName Output file name
results[].totalBytes Total size of the bundle
results[].mappedBytes Bytes covered by source maps
results[].files Map of source file → bytes

Minimal example:

{
  "results": [
    {
      "bundleName": "dist/main.js",
      "totalBytes": 412680,
      "mappedBytes": 398420,
      "unmappedBytes": 14260,
      "files": {
        "src/app/app.ts": { "size": 4812 },
        "src/app/router.ts": { "size": 2140 },
        "node_modules/react/index.js": { "size": 7240 },
        "[unmapped]": { "size": 14260 }
      }
    }
  ]
}

Note: source-map-explorer data is only as accurate as your source maps. Production builds with --sourcemap=hidden or --sourcemap=nosources will show reduced coverage.

rollup-stats

Generated by rollup-plugin-visualizer with the raw-data template. Because Vite builds on Rollup, the same plugin covers both Rollup and Vite projects.

// rollup.config.js or vite.config.js
import { visualizer } from 'rollup-plugin-visualizer';

export default {
  plugins: [
    visualizer({
      template: 'raw-data',
      filename: 'dist/rollup-stats.json',
      gzipSize: true,
      brotliSize: true,
    }),
  ],
};

Fields used:

Field Purpose
tree.children[] Output chunk files (each top-level node is one asset)
tree…children[].uid Leaf module → its part in nodeParts
nodeParts[uid].renderedLength Module size contributed to the chunk
nodeParts[uid].gzipLength / brotliLength Compressed sizes (when gzipSize/brotliSize enabled)
nodeMetas[metaUid].id Real module path; isExternal modules are excluded

Minimal example:

{
  "version": 2,
  "tree": {
    "name": "root",
    "children": [
      { "name": "main-abc123.js", "children": [{ "name": "src/app.ts", "uid": "u1" }] }
    ]
  },
  "nodeParts": {
    "u1": { "metaUid": "u1", "renderedLength": 4812, "gzipLength": 1900, "brotliLength": 1700 }
  },
  "nodeMetas": {
    "u1": { "id": "src/app.ts" }
  },
  "options": { "gzip": true, "brotli": true, "sourcemap": false }
}