feat: add Renamer#123
Merged
Merged
Conversation
graphite-app Bot
pushed a commit
that referenced
this pull request
Jun 17, 2026
Removes the "Auto Assign PR" GitHub Actions workflow that auto-assigned newly opened PRs to their authors when the author was a rolldown org member. <!-- - 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
Jun 17, 2026
#9810) #9755 already made the external default-import name deterministic via `min_by_key((stable_id, name))` plus an always-on stable sort. This refines that path without changing output: - `sort_by` -> `sort_unstable_by`, guarded by `len > 1`: stability is needless since the names are unique `FxHashMap` keys, and this matches the project direction in #9803 (use unstable sort where stability is unneeded). - default-name selection uses `exec_order()` (u32 compare) instead of `stable_id().as_str()` (string compare): cheaper, and consistent with the sibling `external_import_namespace_merger`, which `code_splitting.rs` already orders by `exec_order()`. All rolldown integration snapshot tests pass unchanged. <!-- - 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
Jun 17, 2026
Replace the two-line CODEOWNERS (which only covered AGENTS.md / CLAUDE.md) with a full crate/package-level ownership map derived from git history (all-time + recent commit activity). Owners are the five maintainers @hyf0, @IWANABETHATGUY, @shulaoda, @h-a-n-a, and @sapphi-red. Design rules: - Every area has at least TWO owners so changes can be cross-reviewed. - Global `*` default lists all five (placed first; GitHub uses last-match-wins). - Vite plugin suite folded into a single `/crates/rolldown_plugin_vite_*/` wildcard owned by @shulaoda + @sapphi-red, the two contributors active across all 19 vite crates. - Dev/HMR, core engine, ECMAScript tooling, plugins, and packages assigned to their most active contributors. - AGENTS.md / CLAUDE.md kept unanchored so they match at any depth (root AGENTS.md, .claude/CLAUDE.md, rollup/AGENTS.md). <!-- - 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
Jun 17, 2026
Adds a `meta/design` doc explaining the options normalization pipeline: JS options → NAPI binding options → raw `BundlerOptions` → `NormalizedBundlerOptions`, plus the Rust integration-test config path that deserializes `BundlerOptions` directly from `_config.json`. The doc documents **why each layer exists** and that both frontends converge at the serde-deserializable `BundlerOptions`, normalized once by `prepare_build_context`. It also calls out the test-harness defaulting caveat: the integration-test harness pre-fills several fields (`cwd`, `external`, `input`, entry/chunk filenames, `checks`) before `Bundler::new`, so omitted fixture fields exercise test-harness defaults rather than production defaults. Docs-only change; no runtime code is affected. <!-- - 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
Jun 23, 2026
The CLI `--help` message rendered option names in kebab-case while the parser (and Rollup/Vite) use camelCase. Switch the help-only `options` map and `help.ts` rendering to camelCase, regenerate the CLI e2e snapshots, and update the internal CLI pipeline doc. from #9932 (comment) <!-- - 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! -->
h-a-n-a
added a commit
that referenced
this pull request
Jun 24, 2026
<!-- - 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! --> Add more clarifications on drafting PRs.
h-a-n-a
added a commit
that referenced
this pull request
Jun 24, 2026
<!-- - 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! --> Remove global catch line. It's the author's obligation to request how small changes should be reviewed. This keeps these changes from spamming every maintain's inbox.
leegeunhyeok
added a commit
to rollipop-dev/rolldown
that referenced
this pull request
Jun 25, 2026
<!-- - What is this PR solving? Write a clear and concise description. - Reference the issues it solves (e.g. `fixes rolldown#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! -->
leegeunhyeok
added a commit
to rollipop-dev/rolldown
that referenced
this pull request
Jun 25, 2026
<!-- - What is this PR solving? Write a clear and concise description. - Reference the issues it solves (e.g. `fixes rolldown#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! --> just indent ```js // AS-IS (function () { var __rollipop_modules__ = __rollipop_require__.m = { 1: function() {}, 2: function() {}, 3: function() {} }; })(); // TO-BE (function () { var __rollipop_modules__ = __rollipop_require__.m = { 1: function() {}, 2: function() {}, 3: function() {} }; })(); ```
shulaoda
added a commit
that referenced
this pull request
Jun 26, 2026
…#9948) When two emitted assets have identical content but different names, rolldown deduplicates them by content hash. The surviving asset's [name] was taken from whichever copy emits first, which is non-deterministic. Fix by always choosing the alphabetically-first name. Fixes #9940 Claude was used, the work was reviewed by me. I mostly have Rust experience from advent of code. <!-- - 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! --> --- ### The problem When several assets are emitted with identical content but different names, rolldown deduplicates them by content hash into one output asset. The surviving asset took its `[name]` from whichever copy was emitted first, and because assets are emitted concurrently during module processing that order is not stable. The chosen name flows into `assetFileNames` and changes the `[hash]` of every chunk that references the asset, so byte-identical input could produce different file names from one build to the next. Fixes #9940. ### Deterministic survivor name The survivor is now chosen deterministically: the shortest name wins, with ties broken lexicographically. This is the rule Rollup uses in `finalizeAssetsWithSameSource`, and the same order rolldown already applies when it sorts an asset's `names`, so the chosen `filename` stays consistent with `names[0]`. An earlier version of this PR kept the alphabetically-first name, which ignores length and disagrees with Rollup; it has been changed to shortest-then-lexicographic. ### Fixing a metadata-loss race The first time a hash is seen, the asset is now inserted into `self.files` while the `source_hash_to_reference_id` shard lock is still held, before the reference id becomes visible. Previously the lock was dropped before that insert, so a concurrent duplicate could look up the reference id, find nothing in `self.files` yet, and silently lose its `name` and `originalFileName`. ### Behavior change (Rollup parity) This restores Rollup's behavior. For example, two identical CSS assets named `style` and `style2` now deduplicate to `style-[hash].css`, the shorter name, exactly as Rollup does. Vite's `css-codesplit-consistent` test was flipped to expect `style2` when vite started building with rolldown, precisely because rolldown diverged here; with this fix it can go back to its original Rollup assertion. ### Tests Tests live in `crates/rolldown/tests/rolldown/function/asset_dedup_filename` and cover the shortest name winning regardless of emission order, the shortest name beating the lexicographically-first one, every duplicate's `name` and `originalFileName` being collected and sorted onto the survivor, explicit `fileName` assets being left untouched, and concurrent emission never dropping a name. Each test fails on the current code and passes with the fix. --------- Co-authored-by: shulaoda <[email protected]>
graphite-app Bot
pushed a commit
that referenced
this pull request
Jun 26, 2026
This PR adds a failing test that covers a bug found in vitejs/vite#21626. When lazy bundling is enabled, the following bug exists: ```javascript try { await import('./foo.js'); // throws an error inside } catch (e) { // the error is not caught here and a unhandled error happens } ``` <!-- - 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
Jun 27, 2026
### What this solves The replace plugin's `delimiters` option is a `[string, string]` tuple, but the docs never said what the two elements mean. This clarifies that the first value is matched immediately before a key (left) and the second immediately after it (right), and that both are regular expressions, so the default keeps replacements at word boundaries while skipping property accesses. Docs-only change, no code affected. <!-- - 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! -->
leegeunhyeok
added a commit
to rollipop-dev/rolldown
that referenced
this pull request
Jun 29, 2026
# Description Integrate the Oxc-based React Compiler into Rollipop. This change preserves the existing transform options and introduces a new `react_compiler` field to the NAPI surface, avoiding changes to the current API while keeping the integration maintainable. ## Background The Rolldown team decided to withdraw the Rust React Compiler integration (see the linked X post). However, Rollipop is a hard fork of Rolldown and is focused exclusively on React Native, where React Compiler integration remains valuable. For that reason, this PR integrates the React Compiler independently rather than following the upstream decision. refs: https://x.com/boshen_c/status/2069449703935336846 <!-- - What is this PR solving? Write a clear and concise description. - Reference the issues it solves (e.g. `fixes rolldown#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 1, 2026
…pression (#10062) <!-- - 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! -->
leegeunhyeok
added a commit
to rollipop-dev/rolldown
that referenced
this pull request
Jul 1, 2026
<!-- - What is this PR solving? Write a clear and concise description. - Reference the issues it solves (e.g. `fixes rolldown#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 6, 2026
<!-- - 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! --> Adds fields for vitejs/devtools#171 and vitejs/devtools#172
shulaoda
pushed a commit
that referenced
this pull request
Jul 6, 2026
<!-- - 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! --> Adds fields for vitejs/devtools#171 and vitejs/devtools#172
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 6, 2026
<!-- - 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! --> This PR syncs the missing part in Vite's bundledDev test harness refactor and fixes the flaky dev server tests. In the future, we need to make sure that this default devMode option does not have bad effects to the real world users (we can wait and see if user reports issues for this one) and for now, let's keep the default option as-is.
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 6, 2026
<!-- - 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! --> Adding the convention that was explained in the Vite docs because this also applies to Rolldown plugins. https://github.com/vitejs/vite/blob/a1d73a3879196cfd76b05a364e30b1e6b4bdf757/docs/guide/api-plugin.md?plain=1#L111-L150
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 6, 2026
…tal build (#10107) ### Description Part of #7416. This PR fixes the importer relationship item. The remaining items are listed at the end. #### Problem Importer relationships live in two layers: 1. The `importers` edge list on `ScanStageCache`. It is the authoritative reverse dependency graph, and #7348 already keeps it up to date during partial scans. 2. The materialized `importers`, `importers_idx` and `dynamic_importers` sets on each `NormalModule`, which are derived from that edge list. A partial scan rebuilds the second layer only for the modules it rescans. When editing module A adds or removes an import of module B, or changes it between static and dynamic, the change lands on the sets of B. But B is usually served from cache and never rescanned, so its sets stay stale indefinitely. The stale sets are consumed by: - HMR boundary propagation (`importers_idx`). A patch can miss a newly added importer, whose module instance on the client then silently keeps the old dependency. A patch can also run modules that no longer import the edited file. - `import.meta.hot.invalidate()`, which reads `caller.importers_idx` directly without any rescan. - The link and generate stages on incremental rebuilds (`code_splitting`, `chunk_optimizer`, `on_demand_wrapping`, `create_exports_for_ecma_modules`). - `this.getModuleInfo(id).importers` and `.dynamicImporters`. #### Fix The edge list is already correct, so this PR rebuilds the second layer from it for exactly the affected modules: - `ScanStageCache` gains `modules_with_changed_importers`. `ModuleLoader::mark_module_importers_changed` records the target module next to every mutation of the `importers` edge list during a partial scan. The marks are written straight to the cache so they survive a failed scan. - `ScanStageCache::merge` drains the set and rebuilds the sets of each listed module from the edge list through the new `EcmaView::rebuild_importer_sets`, the same helper the loader uses for rescanned modules. - `merge` also refreshes the `ModuleInfo` exposed to plugins for those modules, because the scan refreshes it only for modules it produced. This keeps `ctx.getModuleInfo(id)` in `advancedChunks` name callbacks and plugin queries consistent with the merged graph. `merge` now takes `&PluginDriver` for this. - The `user_defined_entry_modules` recompute in `merge` now also keeps the modules of `EmittedUserDefined` entry rows. Partial scans do not re-run `buildStart`, so entries emitted via `emitFile(type: 'chunk')` are absent from the scan output's set; without this, the refreshed `ModuleInfo` of such a module would report `isEntry: false` after any partial merge that touches its importers. #### Behavior change in an existing snapshot `delete_file_not_used_anymore` step 2 changes from a patch to a full reload. That step edits an orphaned module whose only importer dropped the import in step 0. The old patch came from walking the stale phantom edge. It ran a module that no longer imports the edited file and shipped dead code to the client. A full reload is the honest answer while orphaned modules remain in the graph state. The ideal result is a noop, because a fresh build would not contain the module at all, but that requires the orphan cleanup tracked in #7416. The test harness forbids executing output in fixtures that hit a full reload, which is why the fixture now sets `"expectExecuted": false`. #### Tests - `hmr/import_added_to_cached_module`: a module adds an import of a cached module. A later edit of the cached module must reach the new importer. Without the fix the patch misses that boundary. - `hmr/import_removed_from_cached_module`: the mirror case. A later edit of the cached module must not run the old importer again. Without the fix the patch still contains it. #### Docs `internal-docs/cache/implementation.md` and `internal-docs/bundler-data-lifecycle/implementation.md` are updated for the new field and the new merge steps. #### Remaining items of #7416 - The state still holds removed modules. Editing an orphaned module therefore triggers a full reload instead of a noop, and its module and AST stay in memory. - There is no general check yet that an incremental build and a full build produce the same states. The new fixtures cover the importer sets only. - There is no recovery story for a failed partial scan. A failed scan leaves `module_id_to_idx` marked as seen for modules whose results never reached the snapshot, so the edge list and the snapshot can drift apart until the affected files change again. - Dynamic import entry points are never removed from the cached entry list when the dynamic import goes away. <!-- - 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 6, 2026
### Description Part of #7416. Stacked on #10107. This PR makes a failed scan harmless to the incremental cache. The remaining items of #7416 are listed at the end. #### Problem A partial scan applies task results as they arrive. When the scan aborts (the typical case is a syntax error in an edited file), the cache is left half updated while the snapshot receives nothing, because `merge` never runs on the error path: 1. Re-scanned modules were flipped to `Seen` in `module_id_to_idx`, so they are treated as fresh even though their new content never landed. The next build silently serves their old code and the error disappears. 2. Completed tasks already rewrote parts of the `importers` edge list, which then disagrees with the snapshot. 3. Newly discovered modules got an index and a `module_id_to_idx` entry, but no slot in the snapshot table. Since new indexes are allocated from the map length and `merge` appends at the table length, a leftover entry shifts every later module by one slot and corrupts all index based lookups. Concrete reproduction (the new fixture): break `b.js`, then edit `a.js`. The rebuild reports success, ships the pre-break `b.js`, and the error overlay is gone. #### Fix A failed partial scan now reverts its cache mutations, so the cache holds a single invariant: between builds it is either empty (no snapshot, only a full scan is possible) or a valid graph any partial scan can build on. There is no third "poisoned" state and no consumer has to reason about failed builds. `ModuleLoader::revert_partial_scan` runs at the scan error exit. The snapshot is never touched by a scan, so it acts as the clean master copy everything else is recovered from: - `importers` is re-derived from the snapshot (`ScanStageCache::derive_importers_from_snapshot`), since every edge is a resolved import record of some module. Slot order is not preserved, and consumers treat slots as sets. The rebuild cost is paid only on failure, the happy path pays nothing. - Existing `module_id_to_idx` entries end the scan at their pre-scan values (`Seen` to `Invalidate` back to `Seen` with the same index), so only the keys inserted for newly discovered modules need removal. The loader records them in `new_module_ids`. - `modules_with_changed_importers` is cleared, matching the reverted edge list. - `barrel_state` is restored from an upfront clone, taken only when lazy barrel is enabled. When disabled the state is empty and never mutated. - The scanned files go into `ScanStageCache::pending_rescans`, a work queue the next partial scan drains. Reverting alone would lose the knowledge that these files changed, and the next build would silently serve their old content. The queue keeps their errors surfacing until the files are fixed. Only files the graph still needs are queued: configured or emitted entries, and files something still imports on the freshest edge state. A broken file whose last import was removed by the very scan that failed is dropped; otherwise its retry would fail every later partial build that a fresh build of the same tree would pass, wedging the session until a restart (new fixture `hmr/error_recovery/remove_import_of_broken_file`). - `transform_dependencies` entries of the newly allocated (and now freed) module indices are dropped, so a later module reusing an index does not inherit them. `Bundler::incremental_bundle` now picks the scan mode from `has_snapshot()` alone. A failed full scan needs no revert, its cache reset already leaves the empty state that forces a full retry. One adjacent panic became reachable and is now handled: a client calling `import.meta.hot.invalidate()` for a module the current graph does not know (for example after a failed full build reset the cache) gets a full reload instead of a server panic. The same applies to `compile_lazy_entry`: a lazy chunk request arriving after a failed full build now returns an error instead of panicking on the missing snapshot. Two consumers of the retry queue needed matching fixes: - `HmrStage::compute_hmr_update` folds the queued files into its stale and changed sets before computing client boundaries. Without this, an edit rolled back by a failed scan reached the server graph on the successful retry but never a client patch, leaving connected clients silently running the old module. The new fixture `hmr/error_recovery/fix_broken_file_delivers_other_edits` asserts the recovery patch contains both the fixed file and the edit made while broken. - The import chain enrichment of unresolved import errors now runs before the revert, while the failed scan's modules still exist in the lookup structures the trace walks. Running it after erased the chain from dev mode diagnostics. Plugin side state (`module_infos`, JS side caches) is not reverted. Hooks that ran during the aborted scan already updated them. This residue is informational, keyed by module id, and overwritten by the next successful scan. The exception is `transform_dependencies`, which is keyed by module index: the entries of indices freed by the revert are dropped, as described above. #### Behavior - The existing error recovery fixtures are unchanged. Breaking a file and fixing the same file still recovers with a plain HMR patch. - New fixture `hmr/error_recovery/remove_import_of_broken_file`: break `b.js`, then remove the `import './b.js'` from `a.js`. That build still surfaces the queued error once, then drops `b.js` from the queue since nothing imports it anymore, and the following edit builds normally again. - New fixture `hmr/error_recovery/edit_other_file_while_broken`: break `b.js`, edit `a.js` (the error surfaces again instead of a fake success with stale code), fix `b.js` (builds succeed again, the queued edit of `a.js` lands in the same scan), edit `a.js` once more (a normal patch, proving the cache stayed incremental through the whole episode). #### Docs The "Cache integrity on a failed build" section of `internal-docs/bundler-data-lifecycle/implementation.md` now documents the revert and the two state invariant. `internal-docs/cache/implementation.md` is updated for the new field and methods. #### Remaining items of #7416 - The state still holds removed modules. Editing an orphaned module triggers a full reload instead of a noop, and its module and AST stay in memory. - There is no general check yet that an incremental build and a full build produce the same states. A dedicated comparison in the test harness would also guard the revert introduced here. - Dynamic import entry points are never removed from the cached entry list when the dynamic import goes away. <!-- - 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 6, 2026
…#10112) ### Description Addresses the review feedback on #10107. Stacked on #10110. Two of the four comments need changes and they live here. The third comment (a failed scan leaves marks that later materialize edge list drift into the HMR importer sets) is fixed by #10110, which reverts all cache mutations of an aborted partial scan. The fourth comment (rescans mark every dependency even when the import set did not change) stays a follow-up, with one note for whoever picks it up: skipping scan output indexes in `merge` is not a pure win, because the loader refreshes `ModuleInfo` only for modules with non empty importers and the merge loop currently covers the empty case. #### Stale doc references `internal-docs/cache/implementation.md` still pointed at three `merge` call sites in `hmr_stage.rs`. The site near `:621` no longer exists. The `Callers` section and the writers table rows for `merge` and `update_defer_sync_data` now cite the two real HMR call sites (the update path and the lazy compile path). #### Restore runtime assertions of `delete_file_not_used_anymore` `"expectExecuted": false` is a fixture wide switch. Only the orphan recreation step needs it, but it also turned off the runtime assertions of the initial build and of every other step, making the whole fixture snapshot only. The fixture is now split: - `delete_file_not_used_anymore` keeps the executing steps (drop the import, then delete the file) and runs its runtime assertions again. - The new `hmr/recreate_orphan_module` fixture carries the full four step sequence (drop the import, delete the file, recreate it, re-import it) as snapshot only. It documents the current limitation that editing or recreating an orphaned module triggers a full reload until the orphan cleanup tracked in #7416 lands. The recreation step cannot stay in the executing fixture, because the re-import step needs the recreated file on disk, so the sequence only makes sense as a whole. <!-- - 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 6, 2026
…fter each HMR step (#10115) ### Description Part of #7416. Stacked on #10112. This adds the test #7416 asks for: one that ensures an incremental build and a full build produce the same states. #### What it does After each HMR step of a dev fixture, the test harness now builds a fresh bundler with the same options and plugins against the current file state and runs a full build. The fresh bundler has no history, so its scan state is by definition the correct answer for the files on disk. The harness then asserts the incremental state matches it: - `importers` and `dynamic_importers` of every module, compared as sets of module ids. Importer entries pointing at modules the fresh build does not know are ignored: those are the outgoing records of orphaned modules, which stay in the state by design (issue #7416). A stale importer entry from a module the fresh build *does* have is still reported. - `importers_idx`, mapped back to module ids since the two sides use different index spaces, with the same orphan filter. - Every import record's kind and resolved target. - Entry points, where the fresh set must be a subset of the incremental set. Extras on the incremental side are allowed for now, because removed modules and stale dynamic import entries are separate open items of #7416. Any difference fails the test with a per module, per field report. #### Why per step instead of once at the end An end of run comparison has a blind spot: a divergence on a cached module is silently repaired as soon as a later step happens to rescan that module, so only the intermediate state is wrong, which is exactly when HMR reads it. This was verified by temporarily reintroducing the bug fixed in #10107 (a cached module keeping a stale importer set). The end of run check passed, the per step check caught it immediately and reported the exact missing importer. #### When it is skipped - Steps whose file state does not build, e.g. the error recovery fixtures while their syntax error is in place. A state that cannot be built has no full build to compare against. - Steps whose incremental build failed. A failed scan is reverted, so the state intentionally stays at the last good build and cannot mirror the current files until a later scan retries them. - Fixtures with lazy barrel enabled. It loads import records on demand, so the loaded subset depends on request history and legitimately differs between a session and a fresh build. #### Opting out `dev.checkStateParity` defaults to `true`, so every existing and future dev fixture gets the check for free (all 38 current HMR fixtures pass with it enabled). A fixture that intentionally documents a known divergence can set it to `false`, and the flag in its config then serves as a visible marker of the known gap until the underlying fix lands. #### Implementation notes - The comparison lives inside the `rolldown` crate behind the existing `testing` feature (`Bundler::assert_scan_state_parity_with`), so it can read the private cache directly and no new public API surface is added. - `DevEngine` gains a `testing` gated `bundler()` accessor, following the existing `get_watched_files` pattern. - `ensure_task_with_changed_files` now sends the whole step as one watch event batch. One event per message spawned one build per file while the awaited future only covered the first, so a multi file step could race the assertion. - The config schema is regenerated by the existing build script. <!-- - 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 13, 2026
<!-- - 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! --> Add `FILE_NOT_FOUND` error that exists in Rollup.
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 14, 2026
…nfig lookups (#10205) Groundwork for #9598 (rebuild when tsconfig changes), on top of #10200. `RawTransformOptions` used to build its own private oxc `Resolver` just for per-file tsconfig discovery. That means two resolvers with two caches: the same tsconfig file is read and parsed twice, and clearing the main resolver's cache (as the watcher already does before every rebuild) never touches the transformer's copy, so the two sides can end up seeing different tsconfig contents. For #9598 we need one clear to invalidate both. `RawTransformOptions` now receives an `Arc<ResolverGeneric<OsFileSystem>>` derived from the main resolver via the new `Resolver::derive_cache_sharing_resolver()`. oxc's `clone_with_options` shares the cache `Arc` when the `yarn_pnp` option matches, and since we clone with the resolver's own options it always matches. Both sides now read the same tsconfig/fs/package.json cache, and one `clear_cache` on the main resolver invalidates both. The `TsConfig` and `yarn_pnp` parameters of `RawTransformOptions::new` are gone because the tsconfig discovery config comes with the shared resolver, which was built from the same `TsConfig` value. Notes for reviewers: `rolldown_common` gains a `rolldown_fs` dependency, which is cycle-free since `rolldown_fs` only depends on `oxc_resolver` and `vfs`. The two Raw-mode arms in `prepare_build_context` became identical after this change and were merged into one. The derived resolver inherits the main resolver's full options instead of oxc defaults, but `find_tsconfig` only depends on the `tsconfig` option, which was already configured identically on both sides, so per-file discovery results are unchanged. The transformer also now reads files through the same `OsFileSystem` instance as module resolution, so the yarn pnp setting is applied consistently. Part of #9598. <!-- - 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 14, 2026
…10257) <!-- - 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! --> Part of #9598 (rebuild when tsconfig changes), on top of #10205. `RawTransformOptions` memoizes the transform options merged from each tsconfig for the lifetime of the bundler. The watch task already clears the resolver cache before every rebuild, so edited tsconfig files are re-read from disk, but the memoized merge results were never dropped, so a rebuild kept transforming with the old tsconfig values. Concretely: edit `useDefineForClassFields` in tsconfig.json, touch a source file to trigger a rebuild, and the output still uses the old semantics. The fix adds `clear_cache` on `RawTransformOptions` and wires it through `Bundler::clear_transform_tsconfig_cache`, which the watch task now calls next to the existing `clear_resolver_cache`. Thanks to #10205 the tsconfig contents themselves live in the cache shared with the main resolver, so this only needs to drop the memoized merge results, not a second resolver cache. Note that tsconfig files are not registered as watch files yet, so editing a tsconfig alone still does not trigger a rebuild. That part comes in a follow-up PR. This PR makes sure that once a rebuild is triggered, it picks up the edits.
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 14, 2026
Fixes the watch-mode part of #9598, on top of the cache clearing PR. tsconfig files were never registered as watch files, so editing one did not trigger a rebuild. Every module read from disk now registers its governing tsconfig as a watch file, using the same mechanism as module files, so both the classic watcher and the dev engine pick it up. Plain JS modules register too because `compilerOptions.paths` also affects how their imports resolve. The extra `find_tsconfig` call is answered from the resolver cache after the first module in a directory. Two watch tests cover auto-discovery and a manual tsconfig path. Each flips `useDefineForClassFields` as the only change and asserts the rebuilt output switches semantics, which exercises this PR together with the cache clearing from the previous one. Known limits, left as follow-ups: files pulled in via `extends` are not watched until oxc-resolver reports them, creating a brand-new tsconfig.json is not detected because the per-file watcher cannot watch missing paths, and a solution-style root tsconfig that only routes to references is not watched since `find_tsconfig` returns the matched reference without reporting the root. <!-- - 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 14, 2026
Part of #9598, on top of #10258. Addresses the review comment there about the dev API. After #10258 the dev engine watches tsconfig files, but being watched is not enough: a tsconfig is neither a module nor a transform dependency, so the HMR mapper observes the change and maps it to `Noop`, and dev output keeps the old transform and resolution results. A tsconfig edit affects every module the tsconfig governs, which neither an HMR patch nor a partial scan can represent, so the only correct reaction is a full rebuild with fresh caches. Discovered tsconfig paths are remembered in a set on `RawTransformOptions` that `discover_tsconfig_file` fills during watch registration. The set deliberately survives `clear_cache`, so the bundling task can still classify a changed path after the caches were dropped. When a changed file hits the set, the bundling task clears the resolver and tsconfig caches and upgrades itself to `TaskInput::FullBuild`. Registering the tsconfig as a transform dependency was considered and rejected: the HMR mapper would patch every module the tsconfig governs instead of doing one clean rebuild, and a pure `Hmr` task never clears the caches, so those patches would still use the stale options. Review notes: detection lives in `BundlingTask`, not the coordinator, because the coordinator must not lock the bundler while a running build holds the lock. The upgrade happens after the `watchChange` hooks so they still see the changed files. The coordinator reads `requires_full_rebuild()` only at scheduling time, so a task that upgrades itself mid-run completes through the normal `InProgress` path. Client notification (a `FullReload` update so browsers refresh automatically) and the dev fixtures come in a follow-up. <!-- - 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 14, 2026
…es (#10262) Part of #9598, on top of the full-rebuild PR. This is the last piece of the tsconfig watching work on the rolldown side. The previous PR makes the dev engine rebuild fully with fresh caches when a known tsconfig changes, but connected clients were not told anything, so the browser kept running the old bundle until a manual refresh. The bundling task now sends a `FullReload` update (reason: "tsconfig change") to every client before the rebuild, matching the ordering of the existing full-reload flow where updates are emitted first and the dev server's build-stable machinery gates the follow-up fetch. Two HMR fixtures cover both sides that a tsconfig governs. `tsconfig_change` flips `useDefineForClassFields` and the rebuilt output switches from a constructor assignment to a class field declaration. `tsconfig_paths_change` remaps `compilerOptions.paths` so the same import resolves to a different file, which proves the shared resolver cache is really cleared, since a stale cache would keep resolving the old target. Both snapshots record the full-reload update with its reason and the rebuilt output. The test harness additionally asserts that the changed tsconfig is present in the watched files and that the incremental scan state matches a fresh full build after each step. Remaining known limits of the tsconfig watching work, tracked on #9598: `extends` chains wait on oxc-resolver reporting the loaded files, creating a brand-new tsconfig.json cannot be watched by the per-file watcher, and a solution-style root tsconfig that only routes to references is not reported by `find_tsconfig`. <!-- - 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 15, 2026
<!-- - 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! --> ## Summary This stack of PRs focus on moving bundled-dev (full-bundle mode) HMR to client-side. This PR adds the two client-side data structures (a **module factory map** next to the existing module cache, and a **module graph** shipped as a payload with `__rolldown_runtime__.registerGraph` in the bundle and patched by deltas), so boundary computation, bubbling, and disposal move from the server to the client runtime. ## Shape changes - Initial/rebuild bundle: Added `__rolldown_runtime__.registerGraph` for storing module graph payload in runtime. - HMR patch: - Replaced `createEsmInitializer` / `createCjsInitializer` with `__rolldown_runtime__.registerFactory` that can be reused for HMR invalidation - Moved `applyUpdates` to the place where web-socket messages are received. It applies the change as soon as the new HMR patch has been executed. (Note: This happens in Vite's dev server `FbmHMRClient`) ## Design and Principles ### Pros - **Each browser tab maintains its own state.** (This works today too, but with a delay: the browser currently tells the server over WebSocket which modules have executed, and whether a module has executed affects HMR boundary computation.) - **Smaller HMR payloads** — send only changed, not-yet-sent factories. Today every update sends the browser all modules on the path from the changed modules to the boundary; we want to send only the changed modules. - **Remove the lazy-compilation dedup code**, and at the same time fix the oversized lazy chunk problem. Today a lazy chunk contains all modules, so multiple lazy modules ship duplicate modules. ### Building blocks of client-side HMR - **Module Factory map** (register / update) — when a module updates, the module code along the whole update chain must re-execute. - **Module Cache** (register / clear) — tells whether a module is registered, which affects HMR boundary computation. - **Module Graph** — drives client-side bubbling. - **Client-side HMR boundary computation, client bubble, module disposal** (clearing the module cache). ### Breaking down Webpack - The Module Factory map and Module Cache exist natively. - Module graph: Webpack gets it by rewriting inside `require`. - The key part of HMR is knowing whether a module has executed, since that affects boundary computation. Dynamic import supports this natively — just check at runtime whether the module cache entry exists. Module execution errors also do not matter, because registering exports is the first step of a Webpack module's execution. ### Rolldown principles - Keep the semantics of the Rolldown initial bundle and the full-rebuild bundle; use scope hoisting. - The server does not compute the HMR boundary. - Smaller patches, smaller lazy chunks. ### Rolldown design - **Module Cache** already exists; we only need to add a **Module Factory map**. - **Module graph:** does not exist today. Because the initial bundle is scope-hoisted, we need another way to deliver the module graph. We can insert a module graph payload into the initial bundle (or a rebuild bundle) that records the edges; during HMR the client then computes importers from it. - **"Has this module executed" check:** once HMR moves to the client, this is natively supported, and there is no delay that makes the HMR boundary computation inaccurate. - **Factory optimizations:** - **Incremental Module Factory** — the initial bundle carries the module graph and registers it directly as a payload. Later HMR updates send only module graph deltas, applied incrementally. - **The server is stateful** — it keeps a per-tab record (the ship map) of each browser tab's factory registration state and registered versions, and uses it to decide whether a factory must be re-sent to the browser. - **After a browser refresh**, the factories along the update chain must be re-sent during HMR. ## Testing Vite commit in `packages/test-dev-server` is checked out to a dedicated commit solely for this refactor. `packages/vite-tests` is now based on the same commit as the one in `test-dev-server` in order to let `hmr` tests pass.
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 15, 2026
<!-- - 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! --> ## Summary For full design and principles, please refer to #10164 (comment). This PR adds the server-side **ship map**: a per-client record of which factory versions each browser tab already has, so patches and lazy chunks carry only changed, not-yet-shipped factories. ## Example The stateful server's ship map would incrementally ship factories that are only outdated or never shipped. ### The module graph ```mermaid flowchart LR app["app.js"] --> foo["foo.js<br/>(import.meta.hot.accept — boundary)"] foo --> bar["bar.js"] bar --> baz["baz.js<br/>(edited twice)"] ``` ### Server & client interaction ```mermaid sequenceDiagram participant S as Server (keeps shipped[C]) participant C as Browser tab C Note over C: initial bundle is scope-hoisted — no factories registered on the client yet Note over S: shipped[C] = { } Note over S,C: ① first edit of baz.js S->>C: patch 1 — factories foo@v0 + bar@v0 + baz@v1 (whole re-run chain, nothing shipped yet) C->>C: re-run baz → bar → foo, foo accepts Note over S: shipped[C] = { foo@v0, bar@v0, baz@v1 } Note over S,C: ② second edit of baz.js S->>C: patch 2 — factory baz@v2 only (foo@v0 and bar@v0 are still current in shipped[C]) C->>C: re-run baz → bar → foo, foo accepts Note over S: shipped[C] = { foo@v0, bar@v0, baz@v2 } ``` The first edit ships the whole re-run chain because the initial bundle is scope-hoisted, so the client holds no factories yet. The second edit ships only `baz` — the ship map says `foo` and `bar` were already delivered and are not stale. Rendered, the flow reads: app.js ──> foo.js ──> bar.js ──> baz.js (accept) (edited) edit ① patch = [foo@v0, bar@v0, baz@v1] shipped[C]: {} -> {foo@v0, bar@v0, baz@v1} edit ② patch = [baz@v2] shipped[C]: baz v1 -> v2, rest untouched
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 15, 2026
<!-- - 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! --> ## Summary For full design and principles, please refer to #10164 (comment). This PR removes the full-reload decision from the server's HMR update type, so the client decides to reload from its own boundary result.
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 15, 2026
…es (#10223) <!-- - 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! --> ## Summary For full design and principles, please refer to #10164 (comment). The dev server tracks which module factories it has shipped per client in #10208. But modules that the entry chunk evaluated at top level never in the ship map. A lazy compile that subtracts only the ship man therefor re-ships factories the client already holds, which causes a size bloat in lazy-compilation chunks. This PR introduces a second per-client record - the `top_level_evaluated` map. This map contains the statically evaluated modules so that these modules are not shipped as factories in lazy compilation chunks again when the factories are not changed and only their exports are needed.
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 15, 2026
…es (#10223) <!-- - 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! --> ## Summary For full design and principles, please refer to #10164 (comment). The dev server tracks which module factories it has shipped per client in #10208. But modules that the entry chunk evaluated at top level never in the ship map. A lazy compile that subtracts only the ship man therefor re-ships factories the client already holds, which causes a size bloat in lazy-compilation chunks. This PR introduces a second per-client record - the `top_level_evaluated` map. This map contains the statically evaluated modules so that these modules are not shipped as factories in lazy compilation chunks again when the factories are not changed and only their exports are needed.
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 15, 2026
<!-- - 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! --> ## Summary For full design and principles, please refer to #10164 (comment). ## The playgrounds Each playground is a small app (`index.html` + JS modules + `dev.config.mjs` + `package.json`) with a `__tests__/*.spec.ts` that edits a file and asserts on the running page. Several port behavior expectations from Vite's HMR tests (the `hmr-hot-off` fixture says so explicitly). | Group | Playgrounds | What they exercise | |---|---|---| | Accept | `hmr-accept-exports`, `hmr-nested-dep-accept` | `hot.accept` receiving new exports; accepting a dep deeper in the graph | | Circular graphs | `hmr-circular-accept-outside`, `hmr-circular-self-accept`, `hmr-invalidate-circular` | accept / self-accept / `hot.invalidate` when the edited module sits in an import cycle | | Lifecycle / state | `hmr-dispose-data`, `hmr-prune` | `hot.dispose` passing state through `hot.data`; `hot.prune` when a module is no longer imported | | Events | `hmr-hot-events`, `hmr-hot-off` | `hot.on` for built-in `vite:beforeUpdate` / `vite:afterUpdate`; `hot.off` removing one listener while another stays | | Dynamic import + lazy compilation | `hmr-lazy-dynamic-import-accept-dep`, `hmr-lazy-dynamic-import-self-accept`, `hmr-not-loaded-dynamic-import` | updates to dynamically imported modules, including under lazy compilation and when the module was never loaded | | Full reload | `hmr-before-full-reload` | behavior around an update that must fall back to a full page reload |
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 15, 2026
<!-- - 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! --> ## Summary Both browser test suites run on a vendored Vite, but each had its own copy: the dev-server harness used the `packages/test-dev-server/vite` submodule, and `packages/vite-tests` cloned `vitejs/vite` from the network on every run. This PR unifies them: the submodule moves to the repo root (`vite/`, tracking the `rolldown-canary` branch), and both suites build and test the same checkout, set up once with `just setup-vite`. ```mermaid flowchart LR subgraph before [Before] S1[packages/test-dev-server/vite submodule] --> H1[dev-server tests] N1[network clone of vitejs/vite per run] --> V1[vite-tests] end subgraph after [After] S2[vite/ submodule at repo root] --> H2[dev-server tests] S2 --> V2[vite-tests] end ``` CI runs on the pinned commit; local runs follow the head of `rolldown-canary`.
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 17, 2026
#10332) Fixes the staleness window pointed out in #10325 (comment): `run.ts` called `ensureViteCheckout()`, which can move `vite/` to a new commit, but nothing rebuilds the dev-server side afterwards. `loadVite()` in test-dev-server only checks that `vite/packages/vite/dist` exists, not that it matches the checkout, so a vite-tests run could silently invalidate the dev-server test results. ## Change **`just setup-vite`** **is the only entry point that touches** **`vite/`.** It sets the commit (the latest `rolldown-canary` rebased onto the latest `main`) and finishes the whole setup (install, vite build, rolldown link) in one pass, so the checkout and the built vite dist can never drift apart. **`packages/vite-tests/run.ts`** **does no setup anymore.** It clones the prepared `vite/` checkout locally and goes straight to testing; when the checkout is missing it fails with a "run `just setup-vite` first" hint, like `loadVite()` already does. The `checkout.ts` import and the tsconfig include are reverted. On CI, the vite-test jobs gain a setup-vite step before `run.ts`, like the dev-server workflow already has. ## Verification - Missing checkout: `run.ts` fails with the "run `just setup-vite` first" hint. - Normal path: `run.ts` clones the prepared checkout and proceeds through install, build, and into the test suites. - `ci.yml` parses, both vite-test jobs have the setup step, and `just lint` is fully green. <!-- - 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 17, 2026
<!-- - 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! --> The `EMPTY_IMPORT_META` warning was no emitted for non-node CJS output. This PR fixes that.
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 22, 2026
…ure shutdown (#10363) ### Description Fixes #8411. Fixes #8747. On the wasm target the binding keeps a refcount (`ACTIVE_TASK_COUNT`) over the shared tokio runtime, and the runtime is torn down when the count reaches zero. The count was seeded at `1` and released by `RolldownBuild.close()`, `Watcher.close()` and `scan()` without any matching acquire, while `DevEngine` never touched it at all. As a result, the first `close()` in the process (for example Vite bundling `vite.config.ts` or the dep optimizer) dropped the count to zero and shut the runtime down under every remaining consumer. The next spawn then panicked with `Access tokio runtime failed in spawn`, which surfaces on StackBlitz as `RuntimeError: unreachable`. This PR makes the refcount strictly paired. Every JS object that outlives a single call and spawns onto the runtime now acquires on create and releases on close: - `ACTIVE_TASK_COUNT` is seeded at `0`, so the runtime lives exactly as long as its holders. - `RolldownBuild` acquires in the constructor and releases in `close()`. The `asyncRuntimeShutdown` static flag and the conditional re-start in `#build` are removed since they only existed to work around the unbalanced count. - `Watcher` acquires in the constructor. It previously only released. - `DevEngine` acquires in `create()` and releases in `close()`. It previously did neither, which is the direct cause of #8411. - `scan()` acquires before scanning and releases in `cleanup()`, which is now idempotent because the error path reaches it from both `catch` and `finally`. Double release is also guarded. `RolldownBuild.close()` and `DevEngine.close()` claim the release before their first await, so a second or concurrent `close()` cannot release twice, and the release happens only after `BindingBundler.close()` settles because that call itself spawns onto the runtime. All of this is a no-op on native targets, where `startAsyncRuntime` and `shutdownAsyncRuntime` compile to empty functions. `binding.d.cts` is regenerated from the updated doc comments. <!-- - 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 22, 2026
### Description Follow-up to #10363, which must land first. Adds regression coverage for the `Access tokio runtime failed in spawn` crash class fixed there. This bug class was invisible to every existing CI test. The runtime acquire and release functions are no-ops on native targets, and no CI test actually executed the WASI binding: the WASI workflow builds the wasm binding and runs the stability test and the examples, but those load the native binding that the same job builds for tooling. So an unbalanced runtime release could only ever crash on StackBlitz, never in CI. The new `tests/wasi/runtime-lifecycle.mjs` is a plain node script following the `test:stability` pattern, wired into the WASI workflow right after the build step. It forces the real wasm binding and covers three sequences: - The #8411 shape: a build that gets closed (Vite bundling `vite.config.ts`), then a `DevEngine` is created and run. - The #8747 shape: a build that gets closed, then `watch()` runs until `BUNDLE_END`. - The invariant behind both: closing one consumer while a `DevEngine` is still alive must not tear the runtime down under the engine. Two details are load-bearing. `NAPI_RS_FORCE_WASI` is set to `error` inside the script before importing rolldown, because `true` silently falls back to the native binding when the wasi files are missing and the test would pass without testing anything. After the import the script also asserts via `require.cache` that `rolldown-binding.wasi.cjs` was really loaded. ### Verification Red and green were produced under identical conditions (same machine, same stable toolchain, napi 3.11.0 on both sides, wasm binding forced and asserted). On `main` (`aa73a6848`, without #10363) the test exits 1 in the first sequence with the exact issue signature: `Access tokio runtime failed in spawn` in napi's `tokio_runtime.rs`, followed by `RuntimeError: unreachable`. On top of #10363 all three sequences pass. To run locally: `pnpm build-wasi:debug` in `packages/rolldown` (dist only contains the wasi files when built with `TARGET=rolldown-wasi`), then `pnpm test:wasi-runtime` in `packages/rolldown/tests`. <!-- - 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 22, 2026
### Description Follow-up to #10363, addressing [this review comment](#10363 (comment)). #10363 made the wasm tokio runtime refcount strictly paired: acquire on create, release on close. But every release still ran as a plain statement after the awaited close calls. If any of those awaits rejects, the release is skipped and the acquire leaks. The count then stays above zero, the runtime is never torn down, and on wasm the park threads hang forever, which is the #8747 symptom in reverse. This is not a regression, the old code had the same shape, but it leaves the pairing guaranteed only on the success path. This PR wraps each release in `try/finally` so it fires no matter how the close settles: - `RolldownBuild.close()` - `DevEngine.close()` - the idempotent `cleanup()` in `scan()` - `Watcher.close()`, which the comment did not name but has the identical pattern The documented ordering is unchanged. `finally` runs only after the awaited close settles, whether it resolves or rejects, so the release still happens strictly after `BindingBundler.close()` is done spawning onto the runtime. The claim-before-first-await guard against double release is also untouched, and the whole change remains a no-op on native targets, where `startAsyncRuntime` and `shutdownAsyncRuntime` compile to empty functions. One pre-existing gap is deliberately left alone: when an early step rejects (for example `stopWorkers()`), the later close calls in the same method are still skipped. This PR only guarantees the runtime release. Making every cleanup step run independently is a separate concern. <!-- - 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! -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Test Plan