| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
The migration derives several independent boolean signals from a package's source tree — browser mode, retained upstream `vitest` module references, and one source-scan per opt-in browser provider. Each ran its own full recursive traversal, reading every eligible TS/JS file once per signal, so a standalone project on the complete-miss path read each source file 5 times. `sourceTreeMatches` is generalized to `sourceTreeMatchesEach`, which evaluates several content predicates in a single pass: each file is read once and offered to every predicate that has not yet matched, unwinding as soon as all are decided. `collectPackageSourceScanSignals` enrolls all the per-package signals that way, and both per-package call sites in the orchestrators use it. The tsconfig `types` short-circuit is preserved: when a tsconfig already settles the retained-module signal, its source predicate is not enrolled at all. The standalone path also stops rescanning the tree for the webdriverio provider, since `providerSourceModes` already holds that result. Per-predicate semantics are unchanged — same traversal order, skip directories, nested-package boundary, and unreadable-file handling. Results are deliberately not shared between the workspace and package phases of a monorepo migration, since config merging runs between them. Closes voidzero-dev#2420
✅ Deploy Preview for viteplus-preview canceled.
|
Sorry, something went wrong.
|
Could you show a before and after speed comparison in the PR description? |
Sorry, something went wrong.
|
Added a Performance section to the description with before/after numbers. Summary, on the full-miss path #2420 describes (median of 15 iterations × 3 rounds, Node 22.22.2, warm cache):
Reads per source file go from exactly 5 to exactly 1, which independently reproduces the amplification the issue reports. Wall time improves ~3.3× rather than 5× because only the read and decode per file are eliminated — the predicates still run over each file's content either way. The description also has a collapsed note on exactly what was timed and how, since the scan module needs its barrel import removed to load without the native binding. Generated by Claude Code |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Closes #2420
Problem
vp migrate derives several independent boolean signals from a package's source tree — browser mode, retained upstream vitest module references, and one source-scan per opt-in browser provider. Each ran its own full recursive traversal via sourceTreeMatches, reading every eligible TS/JS file once per signal.
On the complete-miss path (no browser/provider references, no tsconfig retaining Vitest types, no webdriverio dependency to short-circuit) that is 5 reads per source file for a standalone project, exactly as the issue reports.
Changes
Two deliberate limits:
Per-predicate semantics are unchanged: same traversal order, same skip directories, same nested-package boundary, same "unreadable file is ignored and scanning continues" behaviour.
Performance
Measured on the full-miss path — the worst case, and the one #2420 reports: a standalone project with no browser/provider references anywhere, no tsconfig retaining Vitest types, and no webdriverio dependency to short-circuit a scan.
Each cell is the median of 15 timed iterations after 3 warmups, and each row is the median of three such rounds; run-to-run spread stayed under 8%. Node v22.22.2, Linux x64, 4-core Xeon @ 2.10 GHz, warm page cache.
What is timed is the per-package scan phase exactly as each revision's rewriteStandaloneProject performs it:
The measured read counts came out at exactly 5 per source file before and 1 after, independently reproducing the amplification the issue reports and matching the regression test's expected 5 to be 1.
Wall time falls ~3.3× rather than the full 5× because only the read and UTF-8 decode per file are removed — each file's content is still matched against the same predicates either way. These are warm-page-cache numbers, so they understate the gain on a cold cache.
How this was measuredsource-scan.ts cannot be imported on its own in a bare checkout: it imports projectUsesVitestDirectly from the ../migrator.ts barrel, which transitively reaches the native NAPI binding. That import — along with readPackageJsonIfExists and WorkspacePackage — is used only by workspaceUsesVitestDirectly, which is not on the per-package scan path.
So the benchmark loads each revision's source-scan.ts with its first 40 lines (the import block plus that one function) replaced by a prelude that inlines the three constants it needs from shared.ts and a JSON-parsing stand-in for hasVitestTypesInTsconfig. Everything from line 41 onward is byte-identical to the shipped module at that revision (verified with diff), so every measured function is the real one. The hasVitestTypesInTsconfig stand-in is never actually invoked, because the fixture contains no tsconfig.
The fixture is generated: N plausible ~1.4 KB TS modules, 20 per directory under src/, none containing any scan hint string. Before timing, each run asserts that every signal came back false, so a fixture that accidentally short-circuited a traversal would fail rather than silently produce a flattering number.
Testing
New regression test reads each source file once during a standalone migration counts fs.readFileSync calls against a full-miss fixture and asserts each source file is read once. It also asserts every file is read at least once, so a fixture that stopped exercising the scan would fail rather than silently pass.
Verified in both directions:
Checks actually run on this branch:
Not run: the PTY snapshot suite and ecosystem e2e. This change alters no CLI output, only how many times the same files are read.
AI assistance
Claude Opus 5 wrote the implementation, the test, the benchmark, and this description. The change is agent-authored and has not had a separate human review. The results quoted above are from actual runs, not estimates.
Generated by Claude Code