Repository navigation
fix(dev): force incremental build on in DevEngine::new - #10958
Merged
h-a-n-a merged 1 commit intoSep 23, 2026
Merged
Conversation
The HMR stage reads the scan-stage snapshot through module_table() and index_ecma_ast(), which unwrap ScanStageCache::get_snapshot(). That snapshot is only stored when experimental.incrementalBuild is on. prepare_build_context already forces it whenever experimental.devMode is set, so Vite is unaffected, but dev() accepts input options with neither flag. The engine then boots fine and panics the rolldown-worker thread on the first file change, unwrapping a None snapshot at crates/rolldown/src/types/scan_stage_cache.rs:79. The panic poisons the shared future, so the engine is unusable afterwards. A dev engine cannot work without the snapshot, so enable it at construction rather than leaving the invalid configuration representable. Closes rolldown#10957
o-alexandrov
force-pushed
the
fix/dev-engine-force-incremental-build
branch
from
September 22, 2026 17:42
9a49b79 to
40ffc47
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
Merged
shulaoda
added a commit
that referenced
this pull request
Sep 23, 2026
## [1.2.10] - 2026-09-23 ### 🚀 Features - rolldown_plugin_esm_external_require: prefer 'module.exports' over a namespace spread (#10901) by @isker - watch: support directories in addWatchFile (#10944) by @shulaoda - label code-splitting timing rows (#10896) by @IWANABETHATGUY - separate code-splitting group timing rows (#10892) by @IWANABETHATGUY - clarify callback owners in the timing report (#10890) by @IWANABETHATGUY - add checks.bundlerTimings with deprecated pluginTimings alias (#10883) by @IWANABETHATGUY ### 🐛 Bug Fixes - code-splitting: initialize leaves behind a re-exported namespace import (#10694) by @hyfdev - node: record the WASI target on the WebContainer binding fallback (#10952) by @shulaoda - dev: force incremental build on in DevEngine::new (#10958) by @o-alexandrov - tree-shaking: propagate side effects through cycles (#10893) by @IWANABETHATGUY - deconflict CJS locals that shadow a renamed require wrapper (#10793) by @logaretm - include group indexes in labeled `codeSplitting` timing rows (#10916) by @IWANABETHATGUY - docs: type-check Algolia `indices` option (#10934) by @shulaoda - docs: restore Algolia search (#10929) by @isker - tell code-splitting timing rows apart by position (#10903) by @IWANABETHATGUY ### 🚜 Refactor - rolldown_fs_watcher: remove the single-path API (#10950) by @shulaoda - dev: register watch files through FsWatcher (#10949) by @shulaoda - watch: let FsWatcher own the watched paths (#10948) by @shulaoda - watch: identify watch files by normalized absolute path (#10943) by @shulaoda - plugin: build a plugin-resolved `ResolvedId` in one place (#10921) by @IWANABETHATGUY ### 📚 Documentation - dev: add HMR design, align dev docs and engine comments (#10271) by @h-a-n-a ### ⚡ Performance - batch `sourcemapPathTransform` calls (#10763) by @IWANABETHATGUY - batch `sourcemapIgnoreList` calls (#10762) by @IWANABETHATGUY - hmr: drop the unused kind argument from registerFactory (#10915) by @h-a-n-a ### 🧪 Testing - handle Windows paths in sourcemap callback tests (#10942) by @IWANABETHATGUY ### ⚙️ Miscellaneous Tasks - replace custom `ban-expect-assertions` JS lint with builtin `no-restricted-properties` (#10933) by @isker - deps: update napi (#10959) by @renovate[bot] - deps: upgrade oxc to 0.151.0 (#10939) by @camc314 - deps: update test262 submodule for tests (#10941) by @rolldown-guard[bot] - deps: update npm packages (#10931) by @renovate[bot] - deps: update napi (#10928) by @renovate[bot] - deps: update dependency vite-plus to v0.3.3 (#10914) by @renovate[bot] - deps: update rust crates (#10932) by @renovate[bot] - deps: update github actions (#10930) by @renovate[bot] - deps: update dependency rolldown-plugin-dts to v0.28.6 (#10924) by @renovate[bot] - deps: update crate-ci/typos action to v1.50.2 (#10917) by @renovate[bot] - deps: update dependency @napi-rs/cli to v3.10.4 (#10913) by @renovate[bot] - deps: update napi (#10897) by @renovate[bot] ### ❤️ New Contributors * @o-alexandrov made their first contribution in [#10958](#10958) Co-authored-by: shulaoda <165626830+shulaoda@users.noreply.github.com>
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.
Closes #10957.
Problem
HmrStage'smodule_table()/index_ecma_ast()accessors callScanStageCache::get_snapshot(), which unwraps unconditionally (crates/rolldown/src/types/scan_stage_cache.rs:78). The snapshot only exists whenexperimental.incremental_buildis on.prepare_build_contextalready forces that flag wheneverexperimental.dev_modeis set (crates/rolldown/src/utils/prepare_build_context.rs:279), so Vite'sbundledDevis unaffected. Butdev()accepts input options with neither flag. The engine constructs and builds fine, then panics the worker thread on the first file change:The panic poisons the shared future, so the engine is unusable afterwards. Same unwrap as #9728 / #9730, reached from a plain
transformhook usingaddWatchFile.Fix
A dev engine cannot function without the snapshot, so
DevEngine::newenablesincremental_buildat construction instead of leaving the invalid configuration representable. This mirrors whatprepare_build_contextalready does fordev_mode.I also prototyped the alternative (an early
has_snapshot()check incompute_hmr_update_for_file_changesreturningHmrUpdate::FullReload, matching the existing guard incompile_lazy_entryathmr_stage.rs:542). It works, but it is dead code once the option can no longer be off, so I dropped it to keep the diff minimal. Happy to switch if you prefer defence in depth there.Note on
[lib] test = falsecrates/rolldown_dev/Cargo.tomlhadtest = falseunder[lib], so unit tests in this crate were never compiled or run, including byjust test-rust(cargo test --workspace --exclude rolldown_binding). The crate has no other tests, so this drops the setting rather than working around it. Restore that line if it was deliberate, and tell me where you would prefer the regression test to live.Verification
dev_engine_forces_incremental_build_onasserts the constructed bundler has incremental build enabled.cargo test -p rolldown_devruns it and passes (1 passed).rolldown_bindingwith this change, swapped it into avite@8.3.0install, and ran adev()script with atransformhook callingaddWatchFileon a graph module, with nodevModeand noincrementalBuild. Before: thescan_stage_cachepanic above. After: no panic, and the engine emits a correctPatchcarrying the re-transformed code.cargo test -p rolldown --test integration: 2006 passed, 5 failed. The same 5 fail identically on unmodifiedmainin my environment (missing fixturenode_modulesforcjs_module_lexer_compat/util_deprecate, and thetest262submodule not cloned).cargo fmtandcargo clippy -p rolldown_dev --all-targetsare clean.just test-rustworkspace suite and the Node test suites.