Your production JavaScript ships as a handful of minified chunks with hashed filenames. How do you attribute those bytes back to the original source files and npm packages, and what do you have to be careful about when you do?
answer
- maps connect minified back to original
- measures what survived, not what went in
- unmapped bytes are the runtime glue
- pre-compression numbers, say so
- generating maps ≠ publishing maps
basics
~20 sBuild the production bundle with source maps and run a source-map-based analyzer such as source-map-explorer over each chunk and its map. It walks every generated byte range back to an original file, giving a size breakdown of what genuinely shipped after minification.
solid answer
~50 sSource maps are the only artifact that connects minified output back to original files, so they are the honest basis for attribution. Generate them for the exact production build you deploy, then run a tool that reads them — `source-map-explorer` is the common one — over each chunk plus its `.map`. It attributes each range of generated bytes to the original source it came from, so you get per-file and per-package sizes measured *after* minification and dead-code elimination, rather than from the build's own pre-processing view. Two cautions. First, a slice of every chunk maps to nothing — bundler runtime, helpers, injected glue — and shows up as unmapped bytes; that is expected, not a bug. Second, decide deliberately whether the maps are public. Serving them from the same directory as the bundle exposes your source; the usual compromise is to generate maps in CI, use them for analysis and upload them to error tracking, and keep them out of what the CDN serves.
code
bash · 3 lines# Build exactly what you deploy, then attribute the emitted chunks
npm run build
npx source-map-explorer 'dist/assets/*.js'go deeper
Know that source maps link minified output back to original files, and that tools exist which use them to break a bundle down by source file. Running one on a built app is enough at this level.
Explain why post-minification attribution can rank modules differently from the bundler's own stats, and be able to name the unmapped-bytes bucket and what tends to live in it.
Show that you analyze the exact artifact you deploy, and that you have a considered position on source-map exposure: generated in CI, used for attribution and error tracking, not necessarily served to the public.
Own the standing arrangement — where maps are produced, who may read them, how they reach error tracking — so that production stack traces stay legible and size attribution stays possible without anyone re-litigating it per release.
## Why this problem exists After a production build your output is a few files named something like `main.a91f3c2.js`, with mangled identifiers, inlined helpers and everything concatenated. Nothing in that file says which of your modules or which dependency contributed which stretch of it. Yet that file is the ground truth for what users download — so any size conversation eventually needs a way to point back from it to the code you wrote. ## What a source map gives you A source map is a sidecar file that records, for positions in the generated file, the original file, line and column they came from. It exists for debugging, but the same mapping table answers the size question: take a chunk, walk its byte ranges, look up the original source each one maps to, and sum by file. That is exactly what `source-map-explorer` does, and the output is a treemap or list of original files with their post-minification byte shares. ```bash # Attribute a built chunk back to original sources npx source-map-explorer 'dist/assets/*.js' ``` ## Why this differs from the bundler's own report A stats-based analyzer reports what the bundler *put into* a chunk, using its own record. A source-map-based analyzer reports what *survived* into the file you deploy. The two disagree in useful ways: - Minification collapses code unevenly. Verbose, comment-heavy packages shrink far more than packages carrying data tables, so the ranking can invert. - Dead-code elimination has already run. Code that the stats record counted but the optimiser removed no longer appears. - Cross-module optimisations, inlining and helper hoisting show up in their final form. Because of that, source-map attribution is the number to quote when someone asks "what is actually costing us", and it works regardless of which bundler produced the file — the map is a standard format, so the technique survives a build-tool migration. ## The traps **Analyze the deployed build.** Maps generated from a development or non-production configuration describe a different program. Run the same command your pipeline runs, then analyze its output. **Unmapped bytes are normal.** Bundler runtime, module wrappers, injected polyfills and transpiler helpers often have no original source, and the tool reports them as an unmapped bucket. A small unmapped share is expected. A large one usually means a chunk was analyzed without its map, or that maps were generated at a fidelity level that discards detail — some map settings only record line-level or minimal mappings, which degrades attribution badly. **These are pre-compression bytes.** Attribution runs on the minified file, not the compressed response. Rankings can shift again once compression is applied, particularly for content with heavy internal repetition. Say which basis you are quoting when you report a number. **Decide the exposure question on purpose.** Publishing maps next to your bundle makes your original source readable by anyone who opens DevTools. For plenty of products that is acceptable, and it makes production debugging vastly easier. Where it is not, the standard arrangement is: generate maps during the build, use them for analysis, upload them to your error-tracking service so stack traces stay readable, and exclude them from the artifact the CDN serves. What you should not do is skip generating them entirely — that leaves you with neither attribution nor readable production stack traces. **Third-party code can be opaque.** A dependency published without maps, or shipped pre-bundled and pre-minified, attributes as a single blob under its package path. That still tells you the package is heavy; it just cannot tell you which part of it you are paying for. ## Where it fits in an investigation A practical sequence: read the bundler's treemap first to see the shape of the build and spot duplicates, then run source-map attribution on the real production chunks to get the sizes you will actually argue from, and only then decide what to change. The first view is fast and structural; the second is slower and truthful. Skipping the second is how teams end up removing something that minified down to nothing anyway.
- A dependency shows up as one opaque block with no internal breakdown. Why, and what can you still conclude?It was published pre-bundled and minified without maps, so there is nothing to attribute inside it. You still get a trustworthy total for the package, which is enough to decide whether it is worth deferring or replacing — you just cannot tell which part of it you are paying for without building it from source yourself.
- Why might the ranking change again once you look at compressed sizes?Compression exploits repetition, so code with highly repetitive structure — generated code, long lists, repeated wrappers — collapses far more than dense, varied code. A module that leads on minified bytes can fall behind once compressed, which is why you should say which basis a number is on before anyone plans work around it.
saying these in an interview costs you the question
- Says you cannot analyze a minified bundle at all
- Treats large unmapped bytes as always normal
- Analyzes a development build and reports the numbers
- Assumes generating source maps means serving them publicly
- Quotes minified attribution as if it were transferred bytes