How BundlePulse Works

A full explanation of the analysis pipeline, size data sources, and accuracy expectations.

1. Parse and normalize

BundlePulse parses your package.json and extracts the dependencies and devDependencies fields. Version ranges (caret ^, tilde ~, exact) are resolved to specific versions using the npm registry API. Invalid JSON is rejected with an inline error.

2. Build the dependency tree

For each direct dependency, BundlePulse fetches the package metadata from registry.npmjs.org and recursively resolves its sub-dependencies to a maximum depth of 5. Circular references are detected and flagged without infinite loops. The result is a directed acyclic graph of all packages your project depends on.

3. Fetch size data

Package sizes (gzipped and minified) are fetched from the Bundlephobia API (bundlephobia.com/api/size), which provides the actual gzipped bundle size for each npm package. When Bundlephobia is unavailable, BundlePulse falls back to the npm registry's unpackedSize field and estimates gzip at ~20% of unpacked size. All size data is cached in-memory to avoid redundant API calls.

4. Compute additive cost

The key differentiator. Instead of summing package sizes naively (which double-counts shared sub-dependencies), BundlePulse computes the marginal cost of each direct dependency. For a given package P referenced by N paths in the dependency graph, the marginal cost assigned to each referencing path is: marginalCost = P.gzippedSize / N The additive cost of a direct dependency D is: additiveCost(D) = sum(marginalCost(P) for all P in D's dependency subtree) When summed across all direct dependencies, the total approximates the unique bundle size.

5. Classify tree-shakeability

BundlePulse examines three fields in each package's package.json: • module field — presence of an ESM entry point → "full" tree-shaking • exports map — ESM conditions ("import", ".mjs") → "full" tree-shaking • sideEffects field — false → "full"; array → "partial"; true or absent → "none" Packages without an ESM build (CJS only) are marked "none" — they ship their full size regardless of what you import.

6. Accuracy and limitations

BundlePulse estimates are accurate to within ±15% of Webpack Bundle Analyzer output for typical React and Next.js projects. The main sources of variance: • Your bundler may tree-shake more aggressively than our heuristics predict • Dynamic imports and code splitting can move packages out of the initial bundle • Some packages have multiple entry points with different sizes • Scope hoisting can reduce the actual bundle size below our estimate All numbers are labeled "estimated." For exact figures, run your bundler. For a fast, actionable diagnosis, use BundlePulse.
Questions about the methodology? Email us or open an issue on GitHub.