Skip to content

lib: defer source map payload decoding until first use - #65490

Open
codebytere wants to merge 1 commit into
nodejs:mainfrom
codebytere:perf/source-map-lazy-decode
Open

lib: defer source map payload decoding until first use#65490
codebytere wants to merge 1 commit into
nodejs:mainfrom
codebytere:perf/source-map-lazy-decode

Conversation

@codebytere

Copy link
Copy Markdown
Member

With source maps enabled, stops decoding, reading and parsing every module's source map while the module loads; the payload is resolved the first time a stack trace (or module.findSourceMap()) needs it.

benchmark/module/module-require-source-map.js (new; require() of 1000 ~45-line modules with source maps enabled), 30 runs:

before after
inline (data: URL) maps 3 590 req/s 5 660 req/s +48 % ±4 %
external .map files 4 880 req/s 6 570 req/s +35 % ±2 %
no map comment 7 190 req/s 7 220 req/s n.s.

Under --enable-source-maps, process.setSourceMapsEnabled(true) or NODE_V8_COVERAGE, every module carrying a sourceMappingURL had its map decoded from the data: URL or read from disk, JSON-parsed and its sources resolved while loading, and the per-line length table used for coverage was built with a per-code-point loop over the source. None of that is needed unless a stack trace through that file is later mapped, so applications that ship source maps paid for all of them at startup.

The cache entry now keeps the URL and resolves the payload on the first findSourceMap() for that file, which is what stack trace preparation and module.findSourceMap() go through. Under NODE_V8_COVERAGE the payload is still resolved at load time, since the cache is serialized during shutdown when no more JS may run. lineLengths() splits on \n with indexOf and only falls back to the code point walk when the source contains U+2028/U+2029; its output is unchanged.

Tests: existing source-map, coverage, getCallSites and node-output-sourcemaps tests pass unchanged; they cover mapped stack traces, findSourceMap(), invalid maps and the coverage cache serialization.


Disclosure: the code, benchmark, measurements and this description were written by Claude Code, directed and reviewed by @codebytere.

With source maps enabled, every module that carries a sourceMappingURL
had its map decoded (or read from disk), JSON-parsed and its sources
resolved to absolute URLs while the module was being loaded, and the
per-line length table used for coverage was built with a per-code-point
loop. None of that is needed unless a stack trace is later mapped.

Keep the URL on the cache entry and resolve the payload on the first
findSourceMap() for that file. Under NODE_V8_COVERAGE the payload is
still resolved at load time, since the cache is serialized during
shutdown. lineLengths() now splits on '\n' with indexOf and only falls
back to the code point walk when the source contains U+2028/U+2029.

Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/performance

@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. source maps Issues and PRs related to source map support. labels Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run. source maps Issues and PRs related to source map support.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants