feat: emit the source map scopes field - #275
alexander-akait wants to merge 5 commits into
Conversation
A bundler rewrites an imported binding into a namespace read, and a
source map only maps positions, so a debugger cannot resolve the name
the source used. The Scopes proposal answers that by naming, per scope,
the expression each variable evaluates to.
Add map({ scopes: true }). A source declares what its names read through
a new OriginalSource argument, the chunk stream carries it beside the
source content, and the field is built while the mappings are written
rather than decoded back out of them.
🦋 Changeset detectedLatest commit: 941c833 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #275 +/- ##
==========================================
+ Coverage 98.29% 98.45% +0.16%
==========================================
Files 25 26 +1
Lines 2283 2527 +244
Branches 732 779 +47
==========================================
+ Hits 2244 2488 +244
Misses 37 37
Partials 2 2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Merging this PR will regress 19 benchmarks
|
Requiring it from the two map assembly helpers put the encoder and its lookup table in the module graph of every caller, which the memory benchmarks measured as a constant cost on sources that never emit the field.
The streaming writer reaches none of it, so a map handed in from elsewhere went untested: the early returns, a segment naming no source or one the map lacks, a source resumed after another, a name the map already carries, and a value too large for one base64 digit.
The cases required the helper module directly, so the getter that exposes it on `util` was never run.
Also choose the mapping callback once instead of testing for the scopes
writer per segment. Interleaved against main on one machine, that test
cost OriginalSource.map({ columns: true }) a reproducible 1-3%; with the
callback chosen up front the same measurement is neutral.
Summary
A bundler rewrites an imported binding into a namespace read, and a source map only maps positions, so a debugger cannot resolve the name the source actually used. This adds
map({ scopes: true }), emitting the ECMA-426 Scopes field: a source declares what its names read through a new thirdOriginalSourceargument, the chunk stream carries that beside the source content, and the field is built while the mappings are written rather than decoded back out of them. Needed by webpack/webpack#21999, which otherwise has to carry its own VLQ codec and re-parse every asset'smappings.It also fixes a pre-existing cache bug it would otherwise trip over:
CachedSource's fast-path key inspected onlycolumns, so any two option sets differing elsewhere collided — withscopesthat meant a map built without the field could be served to a caller asking for it, and vice versa.What kind of change does this PR introduce?
feat.
Did you add tests for your changes?
Yes —
test/scopes.js: the option is opt-in, bindings surviveConcatSource,ReplaceSourceand a primedCachedSource, neither cache order leaks or drops the field, and the streaming encoder is asserted byte-identical to decoding a finished map.Does this PR introduce a breaking change?
No.
OnSourcegains an optional fourth argument andMapOptionsan optionalscopesflag; without it nothing is collected or emitted, and the existing 89,895 tests and 1,373 snapshots pass unchanged.If relevant, what needs to be documented once your changes are merged or what have you already documented in this PR?
map({ scopes: true }), theOriginalSourcethird constructor argument, and theutil.scopeshelpers.Use of AI
Yes. Claude Code was used to move the encoder out of webpack, wire the option through the streaming path, and write the tests. The design — a plain boolean option with the bindings riding on the sources, rather than a callback that a cache key cannot see — was mine, and the
CachedSourcebugs above were found by testing that decision rather than assumed.🤖 Generated with Claude Code
https://claude.ai/code/session_01C5WxsJzknrdkVzHV3rL1Uv
Generated by Claude Code