CONCEPT Cited by 1 source
Source-map composition¶
Definition¶
A source map is a file that maps locations in compiled output (JS, WASM,
minified bundle) back to locations in the source the developer wrote. Browser
DevTools reverse the map so a breakpoint on a TypeScript line pauses at the
equivalent point in the shipped JS. Conventionally .map files.
Source-map composition is the discipline, required by any multi-stage compilation pipeline, of combining N single-stage maps into one end-to-end map so that breakpoints set in the first-stage source resolve correctly in the final output.
Why it matters¶
In a single-compile pipeline (TS → JS via tsc/esbuild) the compiler
emits the source map for free. In a two-stage pipeline — which is the shape
of any transpiler-driven language migration — there are two inputs and
two maps, and the browser can only consume one map for the final bundle:
file.sk ──[ transpiler ]──→ file.ts ──[ esbuild ]──→ bundle.js
↓ ↓
file.map ts-to-js.map
└──────── compose ────────────┘
↓
bundle.sk.map
The composed map is built by iterating every entry E in the outer
(ts-to-js) map: look up the TS file and TS code location from E, open
the inner (.sk → .ts) map for that TS file, read off the originating Skew
file and Skew code location, emit (JS location from E, Skew location) into
the composed map.
Why it's load-bearing¶
Without composition, breakpoints set in the first-stage source (the language developers actually write, especially during a gradual migration) either don't fire, fire at the wrong location, or report a different symbol than the one the developer was debugging. This is a monitoring-paradox class of invisible regression in developer tooling — the symptom is "my debugger is lying," which engineers often attribute to their own mistake before suspecting the build.
At codebase scale this compounds: multiple generations of developers land
code with subtle debugger-visibility bugs that no one files a JIRA for,
because the fallback (console.log) does work. Migration velocity
erodes invisibly.
Where it appears¶
- Transpiler-driven language migrations — Figma's Skew → TypeScript
→ JS (canonical). Any migration of the shape
A → B → bundled-outputmust compose. - Cross-language WASM builds — Rust → WASM with debug info, then bundler processing.
- Template/DSL preprocessors that emit a high-level language that's then compiled (e.g. Vue SFC → JS/TS → bundle).
- Minification on top of an already-generated bundle — less common
today because bundlers do both in one pass, but any legacy pipeline
that runs a separate
uglifystep needs composition.
Mechanics (summary)¶
A source map is a list of mappings (generated location) → (source file,
source location, optional symbol name). Composition is:
for each mapping E in outer_map:
gen_loc = E.generated
ts_loc = E.source
ts_file = E.source_file
inner = load_map(ts_file + ".map")
sk_loc = lookup(inner, ts_loc) # reverse inner map
sk_file = inner.source_file_at(ts_loc)
emit (gen_loc → sk_file, sk_loc) into composed_map
Corner cases: one-to-many (a TS range emitted by several JS fragments), many-to-one (an optimiser collapsed two TS statements into one JS expression), and inlined helpers with no first-stage origin. Tooling is thin — most pipelines roll the composition logic by hand inside the build, as Figma did.
Seen in¶
- sources/2024-05-03-figma-typescript-migration — Figma rebuilt the
source-map composition explicitly as part of the Skew→TS migration so
developers could set breakpoints in Skew or TS and have the browser
resolve them in the final JS bundle. Named in the blog as a three-step
pipeline: (1) esbuild emits
ts-to-js.map, (2) the Skew→TS transpiler emits one.sk → .tsmap per file (borrowed logic from the Skew→JS backend's map generator), (3) the build composes them per-entry into the shipped map.
Related¶
- patterns/gradual-transpiler-migration — source-map composition is the hidden developer-experience requirement this pattern places on the migration team.
- systems/esbuild — provides the second-stage
.ts → .jsmap; Evan Wallace (Skew's author, later Figma's CTO) authored esbuild partly on this project's learnings.