Repository navigation
Conversation
## Problem Every file event in a source convention directory reran the whole application analysis. Binding inference and the page scanner each read every source file synchronously, and the page scanner parsed every `*.server.ts` with Oxc again. In a 5,000-page app (the many-pages benchmark), one rescan made 20,006 `readFileSync` calls, two per page file, and took about 800 ms on an idle machine. After the rescan, the routing plugin regenerated `virtual:void-routes` even when the save changed nothing the scan reports. That module lists every page, so Vite re-transformed and re-ran it on every save. In a CPU profile of `vp dev` while editing one page of that app, the rescan took 1.0-1.6 s of each 2.0-2.7 s HMR update, and re-transforming and re-running the route table took most of the rest. The benchmark's HMR time grew from 209 ms at 100 pages to 2.21 s at 5,000. The React adapter's pages and islands plugins also scan pages on their own when files are added or removed and at build start, so the same files were read and parsed several times. ## Fix - `deriveFromSource` (`shared/source-analysis-cache.ts`) caches values derived from a file's contents, keyed by path and analysis kind, and reuses them while the file's inode, size, mtime and ctime are unchanged. Binding inference, page server metadata, component `layout` exports and Markdown frontmatter go through it. The cache is module-level, so the core plugin and the framework adapters share it. - Coarse file system timestamps and inode reuse can leave a rewritten file's stat unchanged. As Git does for racily clean index entries, a file that changed within the last 3 s is always read again, and the dev watcher drops a file's entries on every event. - On a `change` event, the routing plugin compares the scan before and after the rescan. When nothing changed, it skips regenerating route types and entries and leaves `virtual:void-routes` alone; Vite still invalidates the saved module. Adds, deletes, auth config, env files and SSR entries keep the previous behavior. ## Impact Measured on the 5,000-page benchmark app: - A warm rescan reads 2 files instead of 20,006 and takes about 100 ms instead of 530-640 ms. - HMR after editing a page (median of five edits, two runs each): 1,166 and 1,216 ms before, 299 and 248 ms after. The benchmark measured 209 ms at 100 pages, so HMR now barely grows with the page count. - Loader and route handler edits also reach the next SSR response sooner: about 1.6 s to 0.5 s for a loader, and 0.8-1.2 s to 0.1 s for a route handler. ## Verification - New `source-analysis-cache.test.ts`. `pages-scan.test.ts` covers metadata edits between cached scans and fails if the cache ignores the file signature. `plugin-routing.test.ts` covers saves that do and do not change scanned facts. - `vp run check` (33/33, after generating playground codegen in a fresh worktree). - `vp run test --base origin/main`: 511 affected files pass, including the Pages HMR integration suites. - On `vp dev` with the 5,000-page app, edits to a page component, its loader and a route handler all reach the next SSR response. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove redundant cache guidance from AGENTS.md while keeping the implementation unchanged.
Keep the generated routing checkpoint pending until writes and module invalidation succeed, including forced updates with unchanged scan facts. Cover write failures, forced updates, invalidation failures, and recovery to the body-only save fast path.
Stop an unresponsive runtime version probe after ten seconds so test discovery can skip unavailable optional runtimes instead of hanging before Vitest timeouts apply.
This branch has not been deployed
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.
Issue
Saving a page currently re-reads and analyzes unchanged source files, then regenerates routing output even when only the page body changed. This adds unnecessary work as the app grows.
Fix
This change caches file-derived analysis, invalidates edited files through the watcher, and skips route-entry regeneration and route-module invalidation when routing inputs remain unchanged. Recent writes are conservatively re-analyzed to preserve freshness. Failed generation or module invalidation keeps the routing checkpoint pending so a later save retries, including forced updates with unchanged routing facts.
The implementation is shared across React, Vue, Svelte, and Solid Pages. The benchmarks below measure React only.
Results
Measured from file write to the updated heading appearing in Chrome, using Cloudflare dev with local workerd on an Apple M5:
Each fixture includes two additional fixed pages. Results average session medians across ten paired sessions per size, with 360 timed saves overall and seeded, sequential variant ordering after warmup.
Both 1,000-page improvements are statistically significant after Holm correction across six comparisons (
p = 0.0117). The 95% savings intervals are 235–268 ms for HMR and 123–197 ms for reloads. Smaller fixtures show no statistically clear improvement or regression.Validation:
158 focused tests and workspace typechecking.
Four three-page Cloudflare SSR/SSG builds.
Browser checks confirming visible updates, preserved component state, fresh documents for server-page reloads, and no runtime errors.
Regression tests cover retry after generated-file write failures, forced updates with unchanged routing facts, and module invalidation failures. Each case also verifies that successful recovery restores the body-only save fast path.
Optional runtime availability probes now time out after 10 seconds so an unresponsive runtime cannot hang test discovery.
Verification of the retry follow-up: all 21 routing tests, workspace typechecking (33 tasks), and the affected suite (10,789 tests) passed. The full suite passed 14,226 tests but hit the Astro dev server's 20-second startup deadline; all eight Astro tests passed on an isolated rerun. Optional Bun and Deno coverage was skipped because those runtimes were unavailable or unresponsive.