fix(vtz): trigger HMR and clean module graph on file delete#2768
Merged
Conversation
The dev server's change loop called compile_for_browser on every event, which fails for a deleted file — pushing the flow into the compilation- error branch and skipping graph/cache cleanup. Dependents of the deleted file were never HMR-invalidated, so clients kept using stale modules. Fix: - watcher::process_file_change now calls graph.remove_module() on Remove events so ghost nodes don't contaminate future invalidation cascades. - server change loop branches on FileChangeKind::Remove to skip the compile attempt entirely; process_file_change still runs, so dependents are invalidated and HMR broadcasts an Update (or FullReload when the entry file is deleted). Tests: - Unit test in watcher/mod.rs verifying graph cleanup + dependent cache invalidation on Remove. - Parity tests #41/#42 verifying the HMR Update message for a dependent delete and FullReload for entry-file delete. Closes #2764 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Addresses should-fix findings from the adversarial review of #2764. 1. Race between read and write lock in process_file_change. The previous two-phase pattern (read-lock to snapshot dependents, release, write-lock to remove_module) allowed a concurrent browser fetch's graph.update_module() to re-add the deleted module with fresh back-edges in the window between phases. Now holds a single write lock across the dependents snapshot and the graph mutation. 2. CSS-only delete broadcasts a CssUpdate for a 404ing file. A standalone .css delete was treated as CSS-only (no JS dependents), so the HMR client tried to re-fetch the stylesheet URL — which 404s post-delete. is_css_only now additionally requires !is_remove so Remove events escalate to ModuleUpdate(vec![]), handled benignly by the client. Unit-tested. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
viniciusdacal
added a commit
that referenced
this pull request
Apr 18, 2026
Main added native/vtz/tests/parity/hmr.rs (from #2768) after the initial FrameworkPlugin->VtzPlugin rename commit. Apply the rename there too so the Rust test suite compiles after rebase. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
viniciusdacal
added a commit
that referenced
this pull request
Apr 18, 2026
…2773) * docs(vtz): design for plugin rename + React deletion Design doc and six self-contained phase files for renaming the Rust `FrameworkPlugin` trait to `VtzPlugin`, deleting `ReactPlugin`, renaming the TS `createVertzBunPlugin` → `createVertzBuildPlugin`, and removing six orphaned `bun-plugin-shim.ts` files. Approved after three adversarial reviews (DX, Product, Technical). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore(vtz): delete ReactPlugin end-to-end Remove the React framework plugin entirely — the `--plugin` CLI flag, PluginChoice enum, .vertzrc plugin field, package.json auto-detect, ReactPlugin impl (726 lines), embedded React fast-refresh JS assets, and ~15 associated tests. Only VertzPlugin remains. This is part of the vtz-plugin-system cleanup (DESIGN.md §13 decisions 1–2). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(vtz): rename FrameworkPlugin trait to VtzPlugin Pure mechanical rename across 17 Rust files. The trait is vtz-specific and its only impl (VertzPlugin) is framework-internal, so "Framework" was misleading. Signatures unchanged. Part of the vtz-plugin-system cleanup (DESIGN.md §6). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(ui-server): rename bun-plugin to build-plugin Rename the production-build factory from createVertzBunPlugin to createVertzBuildPlugin. Purpose (production build) — not runtime (bun) — drives the name. Dev uses vtz; only the production pipeline consumes this. - Directory: packages/ui-server/src/bun-plugin -> src/build-plugin - Factory: createVertzBunPlugin -> createVertzBuildPlugin - Types: VertzBunPluginOptions/Result -> VertzBuildPluginOptions/Result - Subpath: @vertz/ui-server/bun-plugin -> @vertz/ui-server/build-plugin - vertz re-export: ui-server-bun-plugin.ts -> ui-server-build-plugin.ts Part of the vtz-plugin-system cleanup (DESIGN.md §4, §6). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(cli,benchmarks): fix Phase 3 review findings - Rename mockCreateVertzBunPlugin -> mockCreateVertzBuildPlugin in orchestrator.test.ts and ui-build-pipeline.test.ts (matches the renamed factory consumed by CLI tests). - Update benchmarks/vertz/index.html script src from dist/bun-plugin/fast-refresh-runtime.js -> dist/build-plugin/... - Update ui-server plugin.ts file-header comment: "Unified Bun plugin" -> "Unified production-build plugin" (consistent with the Build-vs-Bun naming rationale). Phase 3 adversarial review in reviews/vtz-plugin-rename-cleanup/phase-03-ts-rename.md. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore: delete 6 orphaned bun-plugin-shim.ts files These shims claimed to bridge to bunfig.toml, but no bunfig.toml exists anywhere in the repo. The scaffold stopped generating them a while ago. Deletes dead code from the pre-vtz era. Deleted: - examples/task-manager/bun-plugin-shim.ts - examples/linear/bun-plugin-shim.ts - examples/entity-todo/bun-plugin-shim.ts - benchmarks/vertz/bun-plugin-shim.ts - packages/landing/bun-plugin-shim.ts - packages/component-docs/bun-plugin-shim.ts No script, package.json, or config references any of these files (verified via repo-wide grep). Apps run on vtz, not bun+bunfig.toml. Part of the vtz-plugin-system cleanup (DESIGN.md §5, §12 Phase 4). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: update for bun-plugin -> build-plugin rename + add changeset - Delete docs/fullstack-app-setup.md (documented a bunfig.toml setup that no longer works; all six shim files deleted in Phase 4). - packages/ui/README.md: "Bun Setup" -> "Build Setup"; reference @vertz/ui-server/build-plugin instead of bun-plugin. - packages/site/pages/guides/deploy/static-sites.mdx: rename createVertzBunPlugin -> createVertzBuildPlugin and retarget the import to @vertz/ui-server/build-plugin. - Add .changeset/vtz-plugin-rename-cleanup.md documenting the full breaking-change set for @vertz/ui-server, vertz, @vertz/runtime (subpath removal, identifier renames, --plugin CLI flag removal, ReactPlugin removal). Part of the vtz-plugin-system cleanup (DESIGN.md §2, §5, §13). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: fix stale bunfig.toml reference in test preload comment The preload file is wired via test.preload in packages/ui-server/vertz.config.ts, not bunfig.toml (which no longer exists in the repo). Update the doc comment accordingly. Sweep from Phase 5 review nit. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(vtz): rename FrameworkPlugin in parity/hmr.rs Main added native/vtz/tests/parity/hmr.rs (from #2768) after the initial FrameworkPlugin->VtzPlugin rename commit. Apply the rename there too so the Rust test suite compiles after rebase. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.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.
Summary
compile_for_browseron every event, which fails for deleted files — pushing flow into the compile-error branch and skipping graph/cache cleanup. Dependents of deleted files kept serving stale modules.process_file_changenow cleans the module graph onRemoveevents under a single write lock (prevents race with concurrentgraph.update_modulefrom browser fetches), and the server loop branches onRemoveto skip compilation while still invalidating dependents. HMR broadcastsUpdatefor a dependent delete,FullReloadfor entry-file delete.CssUpdate(whose URL would 404) toModuleUpdate, unit-tested. Follow-ups filed as Test runner watch mode never populates module graph #2765, Dev server: Modify events with compile errors skip cache/graph maintenance #2766, Refactor: extract dev server file-watcher spawn for testability #2767.Test plan
cargo test --all— green (new unit + parity tests for Remove path)cargo clippy --all-targets -- -D warnings— greencargo fmt --all -- --check— green.tsxfile in a dev-server session; confirm dependents hot-update without stale modulesCloses #2764.