Skip to content

fix(sourcemap): preserve coarse mappings during composition#10249

Merged
graphite-app[bot] merged 1 commit into
mainfrom
codex/issue-10070-root-fix
Jul 15, 2026
Merged

fix(sourcemap): preserve coarse mappings during composition#10249
graphite-app[bot] merged 1 commit into
mainfrom
codex/issue-10070-root-fix

Conversation

@hyfdev

@hyfdev hyfdev commented Jul 13, 2026

Copy link
Copy Markdown
Member

refs #10070.

The behavior to review

This PR makes one choice: when a coarse outer map points to a column before the first mapping on the same line of a more detailed inner map, use that first same-line mapping instead of dropping the generated position.

Rollup makes the same choice when tracing segments. The fallback never crosses a line.

Concrete before and after

User input

main.js is the source written by the user:

export function app() {
  globalThis.side = 1;
  return 42;
}

Generated output

Rolldown produces this chunk. Region comments and the sourceMappingURL line are omitted here, but the code shape is otherwise the fixture's real output:

function app() {
	globalThis.side = 1;
	return 42;
}
export { app };

The generated JavaScript is identical before and after this PR. Only its source map changes.

Before this PR

Asking the composed map where the two generated statements came from returns no original position:

generated 3:1  globalThis.side = 1  ──X──>  null
generated 4:1  return 42             ──X──>  null

In a source-map visualizer, these generated statements have no colored counterpart in the Original pane. A debugger or stack-trace consumer cannot take these positions back to main.js.

After this PR

The same generated positions resolve to the corresponding user-written statements:

Generated output                              User input: main.js

3:1  globalThis.side = 1  ─────────────────>  2:2  globalThis.side = 1
4:1  return 42             ─────────────────>  3:2  return 42

Source-map consumer lines are one-based and columns are zero-based. These are the actual positions asserted by the integration fixture.

In a visualizer, each generated statement now shares a color with its corresponding statement in the Original pane. Selecting either side can identify the other side. Debuggers and stack traces can return to the correct original line; the column is the best same-line position available from the coarse map.

Why the lookup changes

The map chain contains two different levels of detail:

detailed map:  intermediate column 2 -> user source
coarse map:    final column 0        -> intermediate column 0

Before:

final column 0
  -> intermediate column 0
  -> detailed map has no mapping at or before column 0
  -> drop the generated position

After:

final column 0
  -> intermediate column 0
  -> detailed map's first mapping on this line is column 2
  -> use column 2 and preserve the generated position

Lookups between or after existing mappings still use the nearest mapping at or before the requested column. Missing and empty lines still fail. One-field explicitly unmapped segments are skipped in this PR, matching Rollup; #10254 separately preserves those boundaries.

#10074 remains necessary because it makes Rolldown-owned mutation maps more precise. This PR covers coarse external maps and other cases where the producer did not provide matching columns.

Why the snapshots change

The snapshot visualizer writes mappings as:

(original line:column) "original text" --> (generated line:column) "generated text"

Unlike the source-map consumer positions above, these snapshot coordinates are zero-based for both lines and columns. The three snapshots only add mappings; no existing mapping is removed or changed.

Snapshot Newly restored generated mapping Previous first mapping on that generated line Original position used
misc/wrapped_esm 60:1 "(", 60:2 "{" 60:3 "e} = " foo.js 4:4
misc/wrapped_esm 61:1 "(", 61:2 "{" 61:3 "h: " foo.js 7:2
misc/wrapped_esm 73:1 "(", 73:2 "{" 73:3 "destructuring} = " foo.js 30:6
wrapped_esm_default_function 19:0 "init_foo(" 19:9 ");" bar.js 0:23
wrapped_esm_export_named_function 18:0 "init_foo(" 18:9 ");" bar.js 0:27

There are eight added rows in total: six in misc/wrapped_esm, one in each deconflict snapshot. Every addition follows the behavior under review:

new generated column < previous first mapped column on that line
new original position = previous first mapping's original position

For example:

+(0:23) ";\n" --> (19:0) "init_foo("
 (0:23) ";\n" --> (19:9) ");\n"

The coarse map requested generated column 0, while the detailed map's first mapping was at column 9. The fallback associates column 0 with the same original position already used at column 9. It does not move or replace the existing mapping.

Suggested review order

  1. Review the lookup change and source_id guards in crates/rolldown_sourcemap/src/lib.rs.
  2. Review the Rust test where a column-0 coarse token meets a column-2 detailed token.
  3. Review the renderChunk fixture, which exercises the public plugin path and asserts the exact positions shown above.
  4. Check the snapshot table against the eight added snapshot rows.

User impact

  • generated JavaScript, runtime behavior, and bundle size do not change
  • users of source maps regain original locations for lines previously dropped during composition
  • the change matters when a plugin or another transform provides a less column-detailed map than Rolldown's preceding map
  • already resolvable mappings are unchanged

Validation

  • cargo test -p rolldown_sourcemap
  • just test-rust
  • just test-node-rolldown-only fixtures-concurrent.test.ts -t plugin/render-chunk/coarse-sourcemap-composition
  • cargo clippy -p rolldown_sourcemap --all-targets -- --deny warnings

@netlify

netlify Bot commented Jul 13, 2026

Copy link
Copy Markdown

Deploy Preview for rolldown-rs ready!

Name Link
🔨 Latest commit ab584a3
🔍 Latest deploy log https://app.netlify.com/projects/rolldown-rs/deploys/6a572ff00a850b00084f4604
😎 Deploy Preview https://deploy-preview-10249--rolldown-rs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@hyfdev
hyfdev changed the base branch from main to graphite-base/10249 July 13, 2026 07:33
@hyfdev
hyfdev force-pushed the codex/issue-10070-root-fix branch from 248e384 to 204d8b1 Compare July 13, 2026 07:33
@hyfdev
hyfdev changed the base branch from graphite-base/10249 to codex/sourcemap-unmapped-boundaries July 13, 2026 07:33

hyfdev commented Jul 13, 2026

Copy link
Copy Markdown
Member Author

How to use the Graphite Merge Queue

Add the label graphite: merge-when-ready to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@hyfdev
hyfdev changed the base branch from codex/sourcemap-unmapped-boundaries to graphite-base/10249 July 13, 2026 07:50
@hyfdev
hyfdev force-pushed the codex/issue-10070-root-fix branch from 204d8b1 to d862c77 Compare July 13, 2026 07:50
@hyfdev
hyfdev force-pushed the graphite-base/10249 branch from cf12a71 to 705c701 Compare July 13, 2026 07:50
@hyfdev
hyfdev changed the base branch from graphite-base/10249 to main July 13, 2026 07:50
@hyfdev
hyfdev changed the base branch from main to graphite-base/10249 July 13, 2026 07:57
@hyfdev
hyfdev force-pushed the graphite-base/10249 branch from 1c36c89 to 705c701 Compare July 13, 2026 07:57
@hyfdev
hyfdev force-pushed the codex/issue-10070-root-fix branch from d862c77 to c931d1e Compare July 13, 2026 07:57
@hyfdev
hyfdev changed the base branch from graphite-base/10249 to main July 13, 2026 07:58
@hyfdev
hyfdev changed the base branch from main to graphite-base/10249 July 13, 2026 09:49
@hyfdev
hyfdev force-pushed the graphite-base/10249 branch from 1c36c89 to 705c701 Compare July 13, 2026 09:49
@hyfdev
hyfdev force-pushed the codex/issue-10070-root-fix branch from c931d1e to 584ebca Compare July 13, 2026 09:49
@hyfdev
hyfdev changed the base branch from graphite-base/10249 to main July 13, 2026 09:49
@hyfdev
hyfdev marked this pull request as ready for review July 14, 2026 17:02
Copilot AI review requested due to automatic review settings July 14, 2026 17:02

hyfdev commented Jul 14, 2026

Copy link
Copy Markdown
Member Author

Blocking: #10249 must not merge independently of #10254.

The approximate lookup itself looks correct: when a coarse map points before a line's first detailed segment, clamping to that first same-line segment preserves the mapping and matches Rollup's composition behavior.

However, the new source_id guards drop source-less segments. Those segments are explicit unmapped boundaries, not disposable entries: a source-map mapping stays active until the next segment. For example, AAAA,K maps from column 0 and explicitly stops mapping at column 5. If the column-5 segment is removed, the output becomes effectively AAAA, so code after column 5 is incorrectly attributed to the original source.

#10254 restores those unmapped boundaries and adds coverage for both final-map and intermediate-map cases. Since it is stacked on this PR, please merge the complete stack or fold #10254 into this PR before merging #10249.

Also, #10074 already fixed the direct #10070 reproducer. This PR generalizes the fix to coarse external maps; closing #10070 is appropriate only once the unmapped-boundary fix lands as well.

@hyfdev
hyfdev requested a review from sapphi-red July 14, 2026 17:02

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@codspeed-hq

codspeed-hq Bot commented Jul 14, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 16.62%

❌ 1 regressed benchmark
✅ 6 untouched benchmarks
⏩ 10 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
collapse_codegen_chain 11.5 ms 13.8 ms -16.62%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing codex/issue-10070-root-fix (84f1aa1) with main (152ff69)

Open in CodSpeed

Footnotes

  1. 10 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Comment thread crates/rolldown_sourcemap/src/lib.rs
Comment thread crates/rolldown_sourcemap/src/lib.rs Outdated
@hyfdev
hyfdev changed the base branch from main to graphite-base/10249 July 15, 2026 05:55
@hyfdev
hyfdev force-pushed the codex/issue-10070-root-fix branch from 584ebca to e0bd819 Compare July 15, 2026 05:55
@hyfdev
hyfdev changed the base branch from graphite-base/10249 to main July 15, 2026 05:59

sapphi-red commented Jul 15, 2026

Copy link
Copy Markdown
Member

Merge activity

  • Jul 15, 6:55 AM UTC: The merge label 'graphite: merge-when-ready' was detected. This PR will be added to the Graphite merge queue once it meets the requirements.
  • Jul 15, 6:55 AM UTC: sapphi-red added this pull request to the Graphite merge queue.
  • Jul 15, 7:05 AM UTC: Merged by the Graphite merge queue.

refs #10070.

## The behavior to review

This PR makes one choice: when a coarse outer map points to a column before the first mapping on the same line of a more detailed inner map, use that first same-line mapping instead of dropping the generated position.

Rollup makes the same choice when tracing segments. The fallback never crosses a line.

## Concrete before and after

### User input

`main.js` is the source written by the user:

```js
export function app() {
  globalThis.side = 1;
  return 42;
}
```

### Generated output

Rolldown produces this chunk. Region comments and the `sourceMappingURL` line are omitted here, but the code shape is otherwise the fixture's real output:

```js
function app() {
	globalThis.side = 1;
	return 42;
}
export { app };
```

The generated JavaScript is identical before and after this PR. Only its source map changes.

### Before this PR

Asking the composed map where the two generated statements came from returns no original position:

```text
generated 3:1  globalThis.side = 1  ──X──>  null
generated 4:1  return 42             ──X──>  null
```

In a source-map visualizer, these generated statements have no colored counterpart in the Original pane. A debugger or stack-trace consumer cannot take these positions back to `main.js`.

### After this PR

The same generated positions resolve to the corresponding user-written statements:

```text
Generated output                              User input: main.js

3:1  globalThis.side = 1  ─────────────────>  2:2  globalThis.side = 1
4:1  return 42             ─────────────────>  3:2  return 42
```

Source-map consumer lines are one-based and columns are zero-based. These are the actual positions asserted by the integration fixture.

In a visualizer, each generated statement now shares a color with its corresponding statement in the Original pane. Selecting either side can identify the other side. Debuggers and stack traces can return to the correct original line; the column is the best same-line position available from the coarse map.

## Why the lookup changes

The map chain contains two different levels of detail:

```text
detailed map:  intermediate column 2 -> user source
coarse map:    final column 0        -> intermediate column 0
```

Before:

```text
final column 0
  -> intermediate column 0
  -> detailed map has no mapping at or before column 0
  -> drop the generated position
```

After:

```text
final column 0
  -> intermediate column 0
  -> detailed map's first mapping on this line is column 2
  -> use column 2 and preserve the generated position
```

Lookups between or after existing mappings still use the nearest mapping at or before the requested column. Missing and empty lines still fail. One-field explicitly unmapped segments are skipped in this PR, matching Rollup; #10254 separately preserves those boundaries.

#10074 remains necessary because it makes Rolldown-owned mutation maps more precise. This PR covers coarse external maps and other cases where the producer did not provide matching columns.

## Why the snapshots change

The snapshot visualizer writes mappings as:

```text
(original line:column) "original text" --> (generated line:column) "generated text"
```

Unlike the source-map consumer positions above, these snapshot coordinates are zero-based for both lines and columns. The three snapshots only add mappings; no existing mapping is removed or changed.

| Snapshot | Newly restored generated mapping | Previous first mapping on that generated line | Original position used |
| --- | --- | --- | --- |
| `misc/wrapped_esm` | `60:1 "("`, `60:2 "{"` | `60:3 "e} = "` | `foo.js 4:4` |
| `misc/wrapped_esm` | `61:1 "("`, `61:2 "{"` | `61:3 "h: "` | `foo.js 7:2` |
| `misc/wrapped_esm` | `73:1 "("`, `73:2 "{"` | `73:3 "destructuring} = "` | `foo.js 30:6` |
| `wrapped_esm_default_function` | `19:0 "init_foo("` | `19:9 ");"` | `bar.js 0:23` |
| `wrapped_esm_export_named_function` | `18:0 "init_foo("` | `18:9 ");"` | `bar.js 0:27` |

There are eight added rows in total: six in `misc/wrapped_esm`, one in each deconflict snapshot. Every addition follows the behavior under review:

```text
new generated column < previous first mapped column on that line
new original position = previous first mapping's original position
```

For example:

```diff
+(0:23) ";\n" --> (19:0) "init_foo("
 (0:23) ";\n" --> (19:9) ");\n"
```

The coarse map requested generated column 0, while the detailed map's first mapping was at column 9. The fallback associates column 0 with the same original position already used at column 9. It does not move or replace the existing mapping.

## Suggested review order

1. Review the lookup change and `source_id` guards in `crates/rolldown_sourcemap/src/lib.rs`.
2. Review the Rust test where a column-0 coarse token meets a column-2 detailed token.
3. Review the `renderChunk` fixture, which exercises the public plugin path and asserts the exact positions shown above.
4. Check the snapshot table against the eight added snapshot rows.

## User impact

- generated JavaScript, runtime behavior, and bundle size do not change
- users of source maps regain original locations for lines previously dropped during composition
- the change matters when a plugin or another transform provides a less column-detailed map than Rolldown's preceding map
- already resolvable mappings are unchanged

## Validation

- `cargo test -p rolldown_sourcemap`
- `just test-rust`
- `just test-node-rolldown-only fixtures-concurrent.test.ts -t plugin/render-chunk/coarse-sourcemap-composition`
- `cargo clippy -p rolldown_sourcemap --all-targets -- --deny warnings`
@graphite-app
graphite-app Bot force-pushed the codex/issue-10070-root-fix branch from 84f1aa1 to ab584a3 Compare July 15, 2026 06:59
@graphite-app
graphite-app Bot merged commit ab584a3 into main Jul 15, 2026
33 of 34 checks passed
@graphite-app
graphite-app Bot deleted the codex/issue-10070-root-fix branch July 15, 2026 07:05
hyfdev added a commit that referenced this pull request Jul 15, 2026
## Why

This PR is stacked on #10249.

A source-map segment changes the mapping state from its generated column
until the next segment. It is not just a label for one character. A
segment with a source starts a mapped range; a one-field segment with
only a generated column starts an explicitly unmapped range.

For example, the transform fixture returns `AAAA,K` for this generated
line:

```text
columns    012345678901234567
generated  foo(); injected();

column 0   start mapping to main.js
column 5   stop mapping
```

The intended ranges are therefore:

```text
Mapped    generated 0:0–0:5   -> main.js 0:0
Unmapped  generated 0:5–EOL
```

### What a source-map visualizer shows

The blocks below represent the colored spans that a visualizer
associates with the original source. `█` is mapped and `░` is uncolored
or explicitly unmapped.

Before this PR, composition dropped the one-field segment at column 5:

```text
input map      AAAA,K
collapsed map  AAAA

generated  foo(); injected();
visualized ██████████████████
```

With no boundary after column 0, the previous mapping remains active to
the end of the line. `injected()` is colored as if it came from `foo()`;
asking a source-map consumer for the original position of `injected()`
returns the earlier `main.js` mapping.

After this PR, composition preserves the boundary:

```text
input map      AAAA,K
collapsed map  AAAA,K

generated  foo(); injected();
visualized █████░░░░░░░░░░░░░
```

The generated `foo()` remains associated with the original source, while
the semicolon and `injected()` have no original position. A visualizer
leaves that range uncolored, and a debugger or other source-map consumer
no longer attributes it to `foo()`.

The same rule applies when the unmapped boundary appears in an
intermediate map instead of the final map.

Rollup currently drops these one-field segments while collapsing maps.
This PR deliberately differs from that behavior so an explicit unmapped
range remains explicit after composition.

## What changed

- stop tracing when a final or intermediate token has no source
- emit an unmapped token at the corresponding final generated position
- cover final and intermediate boundaries with Rust tests
- cover a plugin transform returning `AAAA,K`

## Validation

- `cargo test -p rolldown_sourcemap`
- `just test-rust`
- `just test-node-rolldown-only fixtures-concurrent.test.ts -t
plugin/transform/explicit-unmapped-boundary`
- `cargo clippy -p rolldown_sourcemap --all-targets -- --deny warnings`
@rolldown-guard rolldown-guard Bot mentioned this pull request Jul 15, 2026
shulaoda added a commit that referenced this pull request Jul 15, 2026
## [1.2.0] - 2026-07-15

### 🚀 Features

- dev: skip shipping factories for newly imported top-level modules (#10223) by @h-a-n-a
- dev: per-client ship map for HMR patch sizing (#10208) by @h-a-n-a
- dev: client-side HMR (#10164) by @h-a-n-a
- dev: send a full-reload update to clients when a tsconfig changes (#10262) by @shulaoda
- treat `import.meta['url']` and `import.meta['ROLLUP_FILE_URL_*']` as side-effect free (#10267) by @sapphi-red
- rewrite `import.meta['url']` (#10251) by @sapphi-red
- add `FILE_NOT_FOUND` error (#10220) by @sapphi-red
- treat `import.meta.ROLLUP_FILE_URL_*` as side-effect free (#10217) by @sapphi-red

### 🐛 Bug Fixes

- sourcemap: preserve unmapped boundaries during composition (#10254) by @hyfdev
- `[format]` in `*FileNames` option for ESM format should be `es` instead of `esm` (#10214) by @sapphi-red
- sourcemap: preserve coarse mappings during composition (#10249) by @hyfdev
- rolldown_plugin_vite_import_glob: support tsconfig paths with `import.meta.glob` (#10167) by @sapphi-red
- dev: clear tsconfig caches for bare full builds (#10276) by @shulaoda
- dev: force a full rebuild when a tsconfig changes (#10261) by @shulaoda
- treat rooted drive-less module ids as absolute in preserveModules naming (#10235) by @IWANABETHATGUY
- watch: rebuild when tsconfig files change (#10258) by @shulaoda
- watch: drop tsconfig-merged transform options on each rebuild (#10257) by @shulaoda
- incorrect `EMPTY_IMPORT_META` warning for `import.meta.ROLLUP_FILE_URL_*` for CJS output (#10221) by @sapphi-red
- deconflict: rename CJS locals shadowing wrapped-ESM namespace objects (#9970) by @IWANABETHATGUY
- rolldown: drop the unused runtime module after entry-level external flattening (#10237) by @IWANABETHATGUY
- rolldown: re-propagate has_dynamic_exports to transitive star importers (#10239) by @IWANABETHATGUY
- tree-shaking: tree-shake destructured dynamic import namespace bindings (#10213) by @logaretm
- s390x: use json-escape-simd 3.1.1 for big-endian JSON escaping fix (#10211) by @satyamg1620

### 🚜 Refactor

- dev: move full-reload to client side (#10207) by @h-a-n-a
- readability follow-ups to the ReplaceWith migration (#10286) by @IWANABETHATGUY
- replace take_in-then-write-back with ReplaceWith and by-value moves (#10285) by @Boshen
- share the main resolver's cache with the transformer's tsconfig lookups (#10205) by @shulaoda
- rolldown: extract the ns star-external __reExport emission rule into LinkingMetadata (#10238) by @IWANABETHATGUY
- rolldown: unify link/generate diagnostics into a Diagnostics accumulator (#10234) by @IWANABETHATGUY
- sourcemap_filenames: drop dead sourcemap-filename plumbing (#10189) by @IWANABETHATGUY
- extract external import symbol merging into a method (#10224) by @IWANABETHATGUY
- rolldown: skip CJS namespace merging under strict execution order (#10203) by @hyfdev
- resolve the manual tsconfig per file instead of once at startup (#10200) by @shulaoda
- rolldown: route interop ESM init emission through a shared init-target view (#10202) by @hyfdev
- rolldown: collapse vestigial wrap-kind state and share chunk sort helper (#10201) by @hyfdev

### 📚 Documentation

- show plugin kinds in JSDoc and each hook's description (#10218) by @sapphi-red
- add an explanation about removing imports from external modules without any messages (#10215) by @sapphi-red

### ⚡ Performance

- sourcemap: owned merge in SourceJoiner::join (4005->5 allocs/chunk) (#10250) by @Boshen
- avoid redundant sourcemap string copies in collapse and minify paths (#10093) by @Boshen

### 🧪 Testing

- code-splitting: establish strict-order review baselines (#10287) by @hyfdev
- dev: add hot API test cases (#10181) by @h-a-n-a
- code-splitting: normalize strict execution order variants (#10277) by @hyfdev
- code-splitting: harden strict execution order coverage (#10252) by @hyfdev
- code-splitting: add strict execution order regressions (#10253) by @hyfdev

### ⚙️ Miscellaneous Tasks

- deps: update github actions (#10241) by @renovate[bot]
- deps: update oxc to 0.140.0 (#10274) by @shulaoda
- update Yunfei's GitHub username (#10275) by @hyfdev
- deps: update napi (#10260) by @renovate[bot]
- deps: update test262 submodule for tests (#10266) by @rolldown-guard[bot]
- deps: update dependency vite-plus to v0.2.4 (#10256) by @renovate[bot]
- deps: update napi (#10240) by @renovate[bot]
- deps: update oxc resolver to v11.24.2 (#10245) by @renovate[bot]
- deps: update rust crates (#10244) by @renovate[bot]
- disable Renovate updates for idna_adapter (#10248) by @shulaoda
- deps: update oxc resolver to v11.24.1 (#10232) by @renovate[bot]
- deps: update rust crate oxc_sourcemap to v8.1.1 (#10233) by @renovate[bot]
- deps: update dependency rolldown-plugin-dts to ^0.27.0 (#10206) by @renovate[bot]
- deps: upgrade sugar_path to v3 (#10230) by @hyfdev
- add `dist-*` to `.gitignore` in sourcemap-filenames/hash-final-content fixture (#10216) by @sapphi-red
- deps: update dependency rust to v1.97.0 (#10209) by @renovate[bot]

### ❤️ New Contributors

* @satyamg1620 made their first contribution in [#10211](#10211)

Co-authored-by: shulaoda <[email protected]>
graphite-app Bot pushed a commit that referenced this pull request Jul 17, 2026
…main (#10318)

## Problem

Since #10164 (and #10293 which unified the checkouts), `packages/vite-tests/run.ts` ran Vite's test suite on the commit pinned by the vite submodule gitlink. The `rolldown-canary` branch of vitejs/vite is regularly rebased and force-pushed, so any pinned commit rots quickly: the current pin `4d1480ca` is no longer on any branch. Worse, test adjustments landing on `rolldown-canary` cannot reach rolldown CI without a manual pin bump. That is exactly why CI on `main` is red right now: the `js-sourcemap` inline snapshot was updated on `rolldown-canary` on 2026-07-15 (for the output change from #10249), but the pin predates that update.

## Change

Restore the pre-#10164 approach from #7633. `run.ts` now does:

```
git clone --branch rolldown-canary https://github.com/vitejs/vite.git
git rebase origin/main
```

so test adjustments landing on `rolldown-canary` take effect right away, and new tests from Vite `main` surface incompatibilities with rolldown early. The rebase identity comes from the existing "Configure Git" step in the vite-test CI jobs.

All inline spec patches are removed from `run.ts`. Test adjustments belong on the `rolldown-canary` branch itself, not in a patch layer inside this repo:

- The `css-codesplit` style-/style2- patch was already dead code: upstream Vite `main` has had the swapped assertions since vitejs/vite#22922.
- The `assets` raw-query skip (#8839) is obsolete: the test passes on current rolldown `main`, in both serve and build.
- The `hmr-full-bundle-mode` invalidate patch is removed. This one still needs a spec fix on `rolldown-canary`: with client-side HMR there is no "hmr invalidate" server log anymore, so the spec should assert that `.invalidation-parent` becomes `child updated` instead. Until that lands on the canary branch, `test-serve` fails this single test.

Also reverts the `tsconfig.json` include added for the now-removed `checkout.ts` import, and updates the `repo-structure.md` description.

## Verification

Full local run against current rolldown `main` (debug build):

| Suite | Result |
| --- | --- |
| test-unit | 65 files passed |
| test-serve | 1 real failure: `hmr-full-bundle-mode > invalidate` (expected, see above) |
| test-build | 93 files passed, `js-sourcemap` snapshot green again |

`environment-react-ssr > deps reload` failed once under full-suite load but passes in isolation (timing flake with the slow debug binding, not a regression).

<!--
- What is this PR solving? Write a clear and concise description.
- Reference the issues it solves (e.g. `fixes #123`).
- What other alternatives have you explored?
- Are there any parts you think require more attention from reviewers?

Also, please make sure you do the following:

- Read the Contributing Guidelines at https://rolldown.rs/contribution-guide/.
- Check that there isn't already a PR that solves the problem the same way. If you find a duplicate, please help us review it.
- Update the corresponding documentation if needed.
- Include relevant tests that fail without this PR but pass with it. If the tests are not included, explain why.

Thank you for contributing to Rolldown!
-->
graphite-app Bot pushed a commit that referenced this pull request Jul 21, 2026
…10368)

### Description

The `node-test-windows` job has been failing on every `main` run since 2026-07-15 (for example [this run](https://github.com/rolldown/rolldown/actions/runs/29795703407/job/88527096422)). The two fixtures added in #10249 and #10254 guard their `load` and `transform` hooks with `id.endsWith('/main.js')`. On Windows, module ids use backslashes, so the guard never matches and the hooks are silently skipped.

With the hooks skipped, `coarse-sourcemap-composition-issue-6399` bundles the on-disk comment-only `main.js` into an empty chunk whose `map` is `null`, so `new TraceMap(null)` throws `Cannot read properties of null (reading '_decodedMemo')`. In `explicit-unmapped-boundary`, the transform never injects `injected()`, so `code.indexOf('injected()')` returns -1 and the assertion fails.

This PR drops the leading slash so the checks become `id.endsWith('main.js')`, which is the pattern every other fixture in the repo already uses and works with both path separators. No production code is touched.
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.

3 participants