dx: halve studio's dev boot with vite 8 bundling - #101
Conversation
Rolldown replaces rollup for the main and preload bundles, which every dev boot rebuilds from scratch: 4.3s to 0.3s, and a prod-shaped build 28.7s to 7.9s. plugin-react 6 drops babel for the refresh transform in favour of oxc and keeps the react compiler on `@rolldown/plugin-babel`, whose preset filters out most modules before babel sees them. vite is held at 8.2.0 because 8.2.1 is inside the minimumReleaseAge window. electron-vite 6 is still a beta; it is the only release that accepts vite 8.
The dev server is listening about a second before the renderer asks for anything, and the generated route tree imports all 40 route files eagerly, so a boot pulls ~625 modules through the browser's six-connection limit. Transforming the route files on the server during that idle window takes a boot from 5.1s to 4.6s. Warming every client file instead is worse (7.5s): the backlog starves the requests actually on the critical path.
📝 WalkthroughWalkthroughThe Studio build setup separates React Compiler Babel integration from the React plugin, updates Vite and Electron tooling versions, and adds renderer server warmup for the main client and route modules. ChangesStudio build tooling
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/studio/package.json (1)
103-103: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse workspace catalog references for the toolchain dependencies.
At Lines 103, 149, and 186,
apps/studio/package.jsonuses literal versions. Add these versions to thecataloginpnpm-workspace.yaml, then use"catalog:"here.Proposed fix
+# pnpm-workspace.yaml + "`@babel/core`": ^7.29.0 + "`@rolldown/plugin-babel`": ^0.2.0 + electron-vite: 6.0.0-beta.1 - "`@babel/core`": "^7.29.0", + "`@babel/core`": "catalog:", - "`@rolldown/plugin-babel`": "^0.2.0", + "`@rolldown/plugin-babel`": "catalog:", - "electron-vite": "6.0.0-beta.1", + "electron-vite": "catalog:",Verify the manifest and catalog:
#!/usr/bin/env bash set -euo pipefail rg -n '"(`@babel/core`|`@rolldown/plugin-babel`|electron-vite)": "catalog:"' apps/studio/package.json rg -n '^ ("`@babel/core`"|"`@rolldown/plugin-babel`"|electron-vite):' pnpm-workspace.yamlAs per coding guidelines:
**/package.json: Package manifests usecatalog:dependency versions; resolve actual catalog versions from the rootpnpm-workspace.yaml.Also applies to: 149-149, 186-186
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/studio/package.json` at line 103, Replace the literal versions for `@babel/core`, `@rolldown/plugin-babel`, and electron-vite in apps/studio/package.json with catalog: references, and add their existing versions to the root pnpm-workspace.yaml catalog. Preserve the resolved dependency versions and verify all three manifest entries and catalog keys are present.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pnpm-workspace.yaml`:
- Line 36: Update the dependency versions in the workspace configuration to
resolvable published releases: replace `@vitejs/plugin-react` ^6.0.5 with the
latest stable published version and Vite ^8.2.0 with the latest stable published
version, or use the exact published beta version only if the beta toolchain is
intentionally required.
---
Nitpick comments:
In `@apps/studio/package.json`:
- Line 103: Replace the literal versions for `@babel/core`,
`@rolldown/plugin-babel`, and electron-vite in apps/studio/package.json with
catalog: references, and add their existing versions to the root
pnpm-workspace.yaml catalog. Preserve the resolved dependency versions and
verify all three manifest entries and catalog keys are present.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 2a7235cf-3af3-45e1-9b62-658c3c77bc29
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (4)
apps/studio/electron.vite.config.tsapps/studio/package.jsonapps/studio/web/vite.config.tspnpm-workspace.yaml
| "@types/react-dom": ^19.2.3 | ||
| "@typescript/native-preview": 7.0.0-dev.20260702.3 | ||
| "@vitejs/plugin-react": ^5.1.2 | ||
| "@vitejs/plugin-react": ^6.0.5 |
There was a problem hiding this comment.
🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
Use published dependency versions.
Line 36 requests @vitejs/plugin-react ^6.0.5, but the public registry currently lists 6.0.4 as latest. Line 44 requests Vite ^8.2.0, while the public registry lists 8.1.5 as latest stable and 8.2.0-beta.0 as the prerelease. Unless CI uses a private registry, a normal install cannot resolve these ranges. (npmjs.com)
Use published stable versions, or declare the exact prerelease version if the beta toolchain is required.
- "`@vitejs/plugin-react`": ^6.0.5
+ "`@vitejs/plugin-react`": ^6.0.4
...
- vite: ^8.2.0
+ vite: ^8.1.5Verify the requested versions:
#!/usr/bin/env bash
set -euo pipefail
npm view `@vitejs/plugin-react`@6.0.5 version
npm view vite@8.2.0 versionAlso applies to: 44-44
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@pnpm-workspace.yaml` at line 36, Update the dependency versions in the
workspace configuration to resolvable published releases: replace
`@vitejs/plugin-react` ^6.0.5 with the latest stable published version and Vite
^8.2.0 with the latest stable published version, or use the exact published beta
version only if the beta toolchain is intentionally required.
Cuts Studio's dev boot roughly in half and its build to under a third, by moving the bundling onto Vite 8 (Rolldown/Oxc) and giving the dev server something to do while Electron starts.
Measured on an M5, 3 runs each. Boot is
studio-drive boot, i.e. spawnpnpm devand wait until the renderer is drivable, which is what an agent validating a change actually pays.dx: move studio's bundling…studio: warm the route modules…Where it went, per boot:
setupBinDirectory…createMainWindow)The boot steps were already fast. Essentially all of it was bundling and the dev server.
The two commits
dx: move studio's bundling onto vite 8 and electron-vite 6— Rolldown replaces Rollup for the main and preload bundles, which every dev boot rebuilds from scratch since there is no persistent cache.plugin-react6 drops Babel for the refresh transform in favour of Oxc, and keeps React Compiler on@rolldown/plugin-babel, whosereactCompilerPresetfilter keeps most modules away from Babel entirely.studio: warm the route modules while electron boots— the dev server is listening about a second before the renderer asks for anything, androuteTree.gen.tsimports all 40 route files eagerly, so a boot pulls ~625 modules through the browser's six-connection limit. Transforming the route files server-side during that idle window is worth ~0.5s.Two things worth a look
Vite is pinned to
^8.2.0, not 8.2.1.minimumReleaseAge: 10080rejected 8.2.1 as too fresh. 8.2.0 measured ~0.2s slower on boot than 8.2.1 did in a scratch worktree. Nothing to do, just noting the policy is why.electron-viteis a beta.6.0.0-beta.1(April 2026, no stable since) is the only release that accepts Vite 8. It has a real bug: it deep-clones the config before resolving async plugin factories, so@rolldown/plugin-babeldies withCannot deep clone non-plain object. Hence the hoistedawait babel(...)inelectron.vite.config.ts, with a comment saying why. Worth an upstream issue if we would rather not carry the workaround.Tried and rejected
experimental.bundledDev): 4.89s, no gain, and it cancels out the warmup. The app code-splits heavily, so unbundled dev only pays for the initial route while bundled dev pays for everything.Testing
check:types,check:build,check:unusedandtest:cipass. Booted the app and opened the PDF viewer, which exercises pdfium WASM plus the module-workeroptimizeDepsworkarounds — the riskiest part of this config.Not verified:
test:browser, Windows, packagedelectron-builderoutput, and the HMR edit loop.check:lintstill fails on two things that fail identically onmainand are untouched here: rootpackage.jsonscript ordering, and a Tailwind class-order error atcomposer-frame.tsx:58.Still on the table
The remaining ~3.5s is renderer-side and structural: the route tree's eager imports are by design (critical route config must load statically), and ~15 of the 40 routes are dev-only
/debug/pages. Options for later, none done here: trim the eager route imports, serve dev over HTTP/2 to lift the six-connection cap, or for booting several copies of the same code, build once andelectron-vite previewper instance so instances 2..N start in ~1.5s.Summary by CodeRabbit
Performance
Chores