You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[heft-isolated-typescript-transpile-plugin] .js.map can list a second, absolute source (another file the worker transpiled), with a wrong mapping #6152
Package: @rushstack/heft-isolated-typescript-transpile-plugin 1.2.30 (SWC via transformFile)
Summary
With sourceMap: true and an ES5 targetOverride, some emitted .js.map files list two sources:
the input file, as a relative path (the plugin rewrites sources[0]);
a different, unrelated file of the same project, as an absolute path.
Exactly one mapping segment points at line 1, column 0 of that second file. The generated code at that position comes from the input file: an ES5 template-literal downlevel ("...".concat(...)). The synthesized node apparently gets a span at the start of another file that the same worker process had already loaded into SWC's source map.
Effects
The source map is wrong: a debugger jumps to an unrelated file.
The absolute path embeds the machine's checkout folder in the build output, so identical inputs produce different bytes on different machines (e.g. CI vs. a developer box). This defeats build-cache and output-equality checks for every downstream bundle that inlines these maps (e.g. webpack with source-map-loader).
Repro
Use a library with about 650 .ts/.tsx files and these emit kinds:
Run heft build --clean. In our case, 8 of 1,328 .js.map files had sources.length === 2. The extra source was always the same file (deterministic for a given file set), e.g.
Decoding mappings gives exactly one segment with source index 1, mapping a "...".concat( in the generated code to line 1, column 0 of the other file.
Where
lib-commonjs/TranspileWorker.js rewrites only parsedMap.sources[0] = relativeSrcFilePath. Any extra source that SWC adds keeps SWC's absolute file name.
Suggested fix
In the plugin (defensive): when parsedMap.sources.length > 1, keep only the input file. Re-encode mappings so that segments pointing at other sources become unmapped generated positions (1-field segments), and trim sourcesContent to match. We apply this as a local patch: it changes only the affected maps (8 of 1,328 in the repro) and leaves every single-source map byte-identical; all source-0 lookups are unchanged.
Upstream in SWC (root cause): the synthesized span in the ES5 template-literal transform should be a dummy span or the original node's span, not a position in another file of the shared source map. This probably deserves a separate SWC issue once confirmed.
AI-generated with GitHub Copilot on behalf of Naman Kanakiya (@namankanakiya); findings were reproduced on real builds by two independent sessions.
Activity