[GH-ISSUE #8106] [Bug] Empty sourceRoot resolves webpack 5 and tsc source-map sources from the URL root #4677

Closed
opened 2026-10-31 00:52:20 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @kaoru0822-kitauji on GitHub (Oct 30, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8106

Originally assigned to: @kaoru0822-kitauji on GitHub.

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

Since 5f702dd6c, a map with "sourceRoot": "" resolves every source from the URL root instead of from the map's directory. webpack 5 and tsc write "sourceRoot": "" by default: 1001 of the 1003 maps in rxjs@7.8.1, and every map in xterm@5.3.0, pdfjs-dist@3.11.174 and @microsoft/signalr@8.0.7.

trace-web-source-location on real npm maps (current main 317bf3fe2):

map URL context source REA resolved_url
rxjs@7.8.1 dist/cjs/internal/Observable.js.map https://cdn.example/npm/rxjs@7.8.1/dist/cjs/internal/Observable.js.map ../../../src/internal/Observable.ts https://cdn.example/src/internal/Observable.ts
xterm@5.3.0 lib/xterm.js.map https://app.test/lib/xterm.js.map webpack://xterm/./src/browser/renderer/dom/DomRenderer.ts https://app.test/webpack://xterm/src/browser/renderer/dom/DomRenderer.ts

analyze-javascript-application uses the same join (sourceMapReference in src/domain/javascript/javascriptSourceMapPaths.ts). On xterm it records all 86 originals as suffix paths such as webpack://xterm/src/common/buffer/Constants.ts. On rxjs, map-relative paths become suffix instead of artifact-relative. From the source (not run, because it needs a browser), analyze-web-bundle resolves source identities through the same function.

Reproduction

  1. npm pack xterm@5.3.0 rxjs@7.8.1 and extract both.
  2. Write an export_web_scripts manifest that exports the generated script, as in the #6726 reproduction.
  3. Run node scripts/rea.mjs trace-web-source-location <manifest> 0 <package>/lib/xterm.js.map https://app.test/lib/xterm.js.map 1 83749 --format json, and the same with rxjs dist/cjs/internal/Observable.js(.map) at line 20, column 4.
  4. Compare with new TraceMap(map, url).resolvedSources (@jridgewell/trace-mapping 0.3.31, the pinned codec) and new SourceMapConsumer(map, url) (source-map 0.7.4).

Expected behavior

trace-mapping 0.3.31 (run) mozilla source-map 0.7.4 (run) Chrome DevTools (source only)
rxjs https://cdn.example/npm/rxjs@7.8.1/src/internal/Observable.ts same sourceRoot.concat(href) with "" leaves the source unchanged (SourceMap.ts parseSources)
xterm webpack://xterm/src/browser/renderer/dom/DomRenderer.ts same same

Impact and scope

These resolved URLs are wrong facts for the default output of webpack 5 and tsc. When the map is not served from the origin root, the URL loses its directory: the rxjs row drops /npm/rxjs@7.8.1. With webpack sources it becomes an impossible URL. Raw reported_source and reported_source_root values are still correct. compare-source-to-bundle still matches these files by suffix, so its effect is smaller there. Its matches are weaker but not wrong in the cases I checked.

REA version

source main 317bf3fe2 (6.8.0)

Runtime and platform

Node 26.5.0; macOS 26 arm64

Target and artifact context

Public npm packages xterm@5.3.0 (webpack 5) and rxjs@7.8.1 (tsc)

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The tables above come from runs I made. The Chrome column is source-derived.

Typed outcome or recovery expected

Not applicable. This is a wrong successful result, not a failure.

Analysis or suspected cause

  • Where it came from: 5f702dd6c (the fix for #6726, about repeated slashes) replaced TraceMap's source resolution with sourceMapReference. That function adds / to every non-null root. Before that commit, TraceMap skipped an empty root. docs/web-source-location.md now documents "An empty root therefore prefixes /".
  • Two readings of the spec:
    • The literal ECMA-426 DecodeSourceMapSources steps (after tc39/ecma426#183) say "if sourceRoot ≠ null and does not end with /, append /". Read literally, "" becomes /.
    • #183 itself says it "matches impl behavior for sourceRoot" and links Chrome, Mozilla and trace-mapping. All three skip an empty root. The spec's only example map with this field, in section 9, uses "sourceRoot": "" with "sources": ["foo.js", "bar.js"], which only makes sense relative to the map.
  • Proposal: treat "" like null in the one shared join, and keep #6726's repeated-slash identity unchanged.
Originally created by @kaoru0822-kitauji on GitHub (Oct 30, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8106 Originally assigned to: @kaoru0822-kitauji on GitHub. ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction ### Observed behavior Since 5f702dd6c, a map with `"sourceRoot": ""` resolves every source from the URL root instead of from the map's directory. webpack 5 and `tsc` write `"sourceRoot": ""` by default: 1001 of the 1003 maps in `rxjs@7.8.1`, and every map in `xterm@5.3.0`, `pdfjs-dist@3.11.174` and `@microsoft/signalr@8.0.7`. `trace-web-source-location` on real npm maps (current main 317bf3fe2): | map | URL context | source | REA `resolved_url` | | --- | --- | --- | --- | | `rxjs@7.8.1` `dist/cjs/internal/Observable.js.map` | `https://cdn.example/npm/rxjs@7.8.1/dist/cjs/internal/Observable.js.map` | `../../../src/internal/Observable.ts` | `https://cdn.example/src/internal/Observable.ts` | | `xterm@5.3.0` `lib/xterm.js.map` | `https://app.test/lib/xterm.js.map` | `webpack://xterm/./src/browser/renderer/dom/DomRenderer.ts` | `https://app.test/webpack://xterm/src/browser/renderer/dom/DomRenderer.ts` | `analyze-javascript-application` uses the same join (`sourceMapReference` in `src/domain/javascript/javascriptSourceMapPaths.ts`). On xterm it records all 86 originals as `suffix` paths such as `webpack://xterm/src/common/buffer/Constants.ts`. On rxjs, map-relative paths become `suffix` instead of `artifact-relative`. From the source (not run, because it needs a browser), `analyze-web-bundle` resolves source identities through the same function. ### Reproduction 1. `npm pack xterm@5.3.0 rxjs@7.8.1` and extract both. 2. Write an `export_web_scripts` manifest that exports the generated script, as in the #6726 reproduction. 3. Run `node scripts/rea.mjs trace-web-source-location <manifest> 0 <package>/lib/xterm.js.map https://app.test/lib/xterm.js.map 1 83749 --format json`, and the same with rxjs `dist/cjs/internal/Observable.js(.map)` at line 20, column 4. 4. Compare with `new TraceMap(map, url).resolvedSources` (`@jridgewell/trace-mapping` 0.3.31, the pinned codec) and `new SourceMapConsumer(map, url)` (`source-map` 0.7.4). ### Expected behavior | | trace-mapping 0.3.31 (run) | mozilla `source-map` 0.7.4 (run) | Chrome DevTools (source only) | | --- | --- | --- | --- | | rxjs | `https://cdn.example/npm/rxjs@7.8.1/src/internal/Observable.ts` | same | `sourceRoot.concat(href)` with `""` leaves the source unchanged ([SourceMap.ts `parseSources`](https://github.com/ChromeDevTools/devtools-frontend/blob/main/front_end/core/sdk/SourceMap.ts)) | | xterm | `webpack://xterm/src/browser/renderer/dom/DomRenderer.ts` | same | same | ### Impact and scope These resolved URLs are wrong facts for the default output of webpack 5 and `tsc`. When the map is not served from the origin root, the URL loses its directory: the rxjs row drops `/npm/rxjs@7.8.1`. With webpack sources it becomes an impossible URL. Raw `reported_source` and `reported_source_root` values are still correct. compare-source-to-bundle still matches these files by suffix, so its effect is smaller there. Its matches are weaker but not wrong in the cases I checked. ### REA version source main 317bf3fe2 (6.8.0) ### Runtime and platform Node 26.5.0; macOS 26 arm64 ### Target and artifact context Public npm packages xterm@5.3.0 (webpack 5) and rxjs@7.8.1 (tsc) ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence The tables above come from runs I made. The Chrome column is source-derived. ### Typed outcome or recovery expected Not applicable. This is a wrong successful result, not a failure. ### Analysis or suspected cause - **Where it came from:** 5f702dd6c (the fix for #6726, about repeated slashes) replaced TraceMap's source resolution with `sourceMapReference`. That function adds `/` to every non-null root. Before that commit, TraceMap skipped an empty root. `docs/web-source-location.md` now documents "An empty root therefore prefixes `/`". - **Two readings of the spec:** - The literal ECMA-426 `DecodeSourceMapSources` steps (after tc39/ecma426#183) say "if sourceRoot ≠ null and does not end with `/`, append `/`". Read literally, `""` becomes `/`. - #183 itself says it "matches impl behavior for `sourceRoot`" and links Chrome, Mozilla and trace-mapping. All three skip an empty root. The spec's only example map with this field, in section 9, uses `"sourceRoot": ""` with `"sources": ["foo.js", "bar.js"]`, which only makes sense relative to the map. - **Proposal:** treat `""` like null in the one shared join, and keep #6726's repeated-slash identity unchanged.
bsakaguchi 2026-10-31 00:52:20 +00:00
  • closed this issue
  • added the
    bug
    triage
    labels
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4677
No description provided.