Skip to content

perf(dev): 6.5x faster dev boot + fix Windows spawn ENOENT#196

Open
Zen0-99 wants to merge 3 commits into
CoreBunch:mainfrom
Zen0-99:boot/launch-speed
Open

perf(dev): 6.5x faster dev boot + fix Windows spawn ENOENT#196
Zen0-99 wants to merge 3 commits into
CoreBunch:mainfrom
Zen0-99:boot/launch-speed

Conversation

@Zen0-99

@Zen0-99 Zen0-99 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Gate the React Compiler to production builds only. It was running its full babel pass over every .tsx module on every dev start, accounting for a large share of the ~45s first-load transform cost.
  • Preload the editor body chunk in parallel with the page render, and skip the 9 sibling workspace-page prewarms in dev (they forced ~20s of Vite transforms and starved the editor of CPU).
  • Add a Windows fallback to scripts/lib/freePort.ts (netstat/tasklist) so the dev port probe works when lsof/ps are not on PATH.
  • Fix scripts/dev.ts child spawning on Windows: bun is a .cmd shim and vite is not on the child's PATH, so Bun.spawn(['bun', ...]) threw ENOENT. Children now run through process.execPath (the real bun.exe) - bun for its own entry, bun executing node_modules/vite/bin/vite.js for the dev server.

Measured result: dev boot 47.7s -> 7.4s (6.5x).

Why

bun run dev presented two waits: a ~20s waiting screen before the admin UI painted, then a second wait for the editor chunk ("Editor is still loading - Retry"). An instrumented boot corridor showed the dominant cost was Vite's per-module transform in dev - largely the React Compiler babel pass on every module every start - plus the editor chunk being fetched serially after first paint and the sibling workspace pages being prewarmed up front. Separately, the Windows spawn bug (a .cmd shim) blocked bun run dev entirely with ENOENT.

Test

  • bun run dev boots clean: [server] Listening on http://localhost:3001 and VITE ready in ~4s - no ENOENT.
  • Editor is interactive on /admin/site with no Retry screen; the sibling workspace pages (PluginPage, AiPage, ...) are gone from the first-load wait.
  • Confirmed process.execPath resolves to the real bun.exe, node_modules/vite/bin/vite.js exists, and Bun.which('vite') is null (so the explicit path is required).
  • bun test src/tests/architecture/bundle-size-budgets.test.ts unaffected: the editor body stays a separate lazy chunk (preload changes fetch timing, not bytes).

- React Compiler: run in build only (was adding a full compiler pass to every module transform in dev, ~45s first-load cost)

- Preload the editor body chunk in parallel with page render; skip the 9 sibling workspace-page prewarms in dev (they forced ~20s of transforms and starved the editor)

- freePort: add Windows netstat/tasklist fallback

- dev.ts: resolve bun via process.execPath and other bins via Bun.which so child spawns don't ENOENT on Windows shims
On Windows the launched 'bun' is a .cmd shim (Bun.spawn(['bun',...]) -> ENOENT) and 'vite' is not on the child's PATH (Bun.which('vite') is null). Resolve both through process.execPath: bun for its own entry, bun executing node_modules/vite/bin/vite.js for the dev server.
Adopt upstream CoreBunch#193's bunCommand/bunRunCommand helpers (process.execPath-based, same Windows fix) for child spawning; drop the now-redundant resolveCommand. Keep the Windows netstat/tasklist fallback in freePort.findPortHolders (superior to upstream's skip-on-Windows) and fix the re-probe loop's sleep spawn, which ENOENT'd on Windows.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants