Skip to content

feat: Embed source content and allow setting the source file name - #104

Merged
timfish merged 4 commits into
nodejs:mainfrom
Lms24:fix/sources-content-source-file-name
Oct 20, 2026
Merged

timfish merged 4 commits into
nodejs:mainfrom
Lms24:fix/sources-content-source-file-name

Conversation

@Lms24

@Lms24 Lms24 commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Currently, the Transformer::transform method names the source in its generated sourcemap <moduleName>/<filePath> (for example ioredis/built/Redis.js) and doesn't embed the file's content. Bundlers resolve that name against the project root (/app/ioredis/built/Redis.js), but the actual file lives in node_modules (e.g. /app/node_modules/ioredis/built/Redis.js).

Tools that follow the map back to the original code, then can fail with ENOENT for every chunk that contains an instrumented module. A concrete example is Sentry's source map upload in Sveltekit where we use sorcery to walk a chain of source maps to flatten them (to get correct source maps linking back to the actual source code instead of an intermediate build output).

This PR proposes two changes:

  • Embed the original code as sourcesContent. With the code inside the map, tools don't need to read the source file from disk. The map still works when the path is wrong, or when the file isn't there, for example after the map is uploaded somewhere else.
  • Add an optional { sourceFile } argument to Transformer::transform that sets the source name, so bundler plugins can pass the module's real path. Callers that don't pass it keep the current source name. In a follow-up PR, @apm-js-collab/code-transformer-bundler-plugins will pass each module's absolute path as sourceFile, so the maps it returns point at real files on disk.

If reviewers prefer, I can also remove the embedding part of the PR, since it's not strictly needed for Sentry (we inline sourcesContent before we upload source maps anyway). Might be helpful for others though.

AI disclosure: Code written with Claude Code and was reviewed by me. PR description written myself.

Context: getsentry/sentry-javascript#25329

@Lms24 Lms24 changed the title feat: Embed source content and allow setting the sourcemap source name feat: Embed source content and allow setting the source file name Oct 13, 2026
@Lms24
Lms24 marked this pull request as ready for review October 13, 2026 15:52
@jsumners-nr

Copy link
Copy Markdown
Contributor
  • Embed the original code as sourcesContent. With the code inside the map, tools don't need to read the source file from disk. The map still works when the path is wrong, or when the file isn't there, for example after the map is uploaded somewhere else.

Does this string live in memory for the life of the process?

@Lms24

Lms24 commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor Author

Good point, thanks for raising! I'm unfortunately not a 100% familiar with Orchestrion but I believe for runtime instrumentation via tracing-hooks, this should be discarded from memory as soon as the transform ran. For runtime, the source maps don't get consumed. If I'm missing something here, or we generally want to err on the side of caution, I can also remove the embedding part from the PR.

@isaacs

isaacs commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

(reviewing, but just re the comments above @jsumners-nr and @Lms24)

The map is always generated when ast exists, also for the runtime hooks.

tracing-hooks uses only .code from the result and drops .map, so nothing holds the map string after the call. The cost is transient, just one more JSON-escaped copy of the module source per transform, plus the JSON.stringify work. It does not live for the life of the process, unless a caller keeps the result object.

Suggestion: no change needed for this PR. As future work, runtime callers do not need a sourcemap at all. An option to skip map generation (or to generate it lazily) would save more than this PR adds, but I'd argue it's out of scope here.

@isaacs isaacs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this. It keeps the change at the one place that builds the map, and adds an options object rather than a 5th positional argument, which leaves room for more options. The default source name does not change, so existing callers only see the new sourcesContent. Embedding the source is the safer of the two changes: it makes the map self-contained no matter what path the caller gives, and its cost is transient for the runtime hooks.

The weak point is the input-sourcemap path. The transform doesn't compose with an earlier map, and instead merges two maps in different coordinate systems. This PR isn't the cause of that, but it puts a real file path and the intermediate content on top of it.

I recommend fixing the composition with applySourceMap, handling null and '' options, and updating the README. With those, this is good to go, imo.

Comment thread lib/transformer.js Outdated
Comment thread lib/transformer.js Outdated
Lms24 and others added 3 commits October 14, 2026 10:30
Co-authored-by: isaacs <i@izs.me>
Copying the input map's mappings into the generator mixed two
coordinate systems and never resolved output positions back through
the input map. Build a fresh generator for the transform and apply
the input map to it, so positions resolve to the original source.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants