Repository navigation
feat(bolt-vite-react-ts): upgrade to vite 8 - #132
Draft
sheepsteak wants to merge 4 commits into
Draft
sheepsteak wants to merge 4 commits into
sheepsteak wants to merge 4 commits into
Conversation
Bump vite to ^8.3.3 and @vitejs/plugin-react to ^6.1.2 and regenerate the lockfile. Make the build test tolerant of `-` in Vite's base64url hashes and of readdir ordering.
|
|
sheepsteak
marked this pull request as ready for review
October 13, 2026 14:45
geotrev
approved these changes
Oct 13, 2026
sheepsteak
marked this pull request as draft
October 13, 2026 15:30
preview.getByText() and preview.getByRole() from @webcontainer/test return locators scoped to the <iframe> element without entering it, and awaiting them doesn't wait for anything, so the dev test passed without checking the preview. Wait from Playwright's side through page.frameLocator() instead, since the preview is cross-origin and in-page queries can't see into it. With a real assertion the test failed on both Vite 5 and Vite 8: restoring the setup() snapshot drops the executable bit from node_modules/vite/bin/vite.js, so `npm run dev` exits with `spawn vite EACCES`. Install in beforeEach instead of restoring the snapshot.
3 of 5 tasks
Move the template from Vite 7 to Vite 8.3.5 and plugin-react to 6.1.2. Ship @rolldown/binding-wasm32-wasi 1.2.16, matching the locked rolldown. Rolldown can't load its native binary in a WebContainer, and its runtime fallback downloads the WASM binding on every boot. Installing it up front removes that download: cold dev ready drops from ~7.4s to ~1.5s. Vite 8.3.5 resolves rolldown 1.2.16, whose binding ships @emnapi beta.2 and pins @napi-rs/wasm-runtime 1.2.6, so the binding and runtime match without an overrides entry.
Rolldown 1.2.16 resolves @emnapi 2.0.0-beta.2 with @napi-rs/wasm-runtime 1.2.6 on its own, so the binding loads without the pin. The runtime download still happens on every new WebContainer, adding about 6s to the first dev start, but the template no longer carries a version-pinned devDependency that has to track rolldown.
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.
Problem
bolt-vite-react-tswas on Vite 5 (vite ^5.4.2) until Vite 7 landed in #134. Vite 8 was blocked by a WebContainer-only problem: Rolldown can't load its native binary there, and its runtime fallback downloads@rolldown/binding-wasm32-wasiwithpnpmon the first import. That download sat in front of every cold dev start, and/tmpdoesn't survive a new boot.Solution
Move the template to Vite 8.3.5 and
@vitejs/plugin-reactto^6.1.2.Ship
@rolldown/binding-wasm32-wasias a devDependency so Rolldown finds it locally and never runs the runtime download. On normal machines the native binary still loads first, so nothing changes there.This follows the pattern from #137 (the Nuxt starter fix that bolt#8821 pointed at), with one difference: #137 also needed an
overridespin on@napi-rs/wasm-runtime, and this does not. See below.Implementation Details
vite ^8.3.5,@vitejs/plugin-react ^6.1.2. Vite 8 bundles with Rolldown and Oxc, and uses Lightning CSS forbuild.cssMinify.css.transformerstill defaults topostcss, sopostcss.config.jsand Tailwind 3 work unchanged.@rolldown/binding-wasm32-wasiat exactly1.2.16, matching therolldownversion Vite 8.3.5 resolves (~1.2.14). Rolldown's loader tries the native binary, then a locally installed binding, and only then the runtime download. The package has nocpu/osrestriction, so it installs everywhere.overridesneeded: the bug behind fix(nuxt): bundle rolldown wasm binding for webcontainer #137 was version skew. Bindings up to 1.2.15 pin@emnapi2.0.0-alpha.5with@napi-rs/wasm-runtime ~1.2.5, but 1.2.6 raised its@emnapipeer range to2.0.0-beta.2, so an old binding plus a hoisted 1.2.6 failed withthis.bridge.setLastError is not a function. Binding 1.2.16 ships@emnapibeta.2and pins1.2.6itself, so the tree resolves consistently with no override. I confirmed the lockfile holds a single set (@emnapi/*beta.2, runtime 1.2.6) with no nested duplicate.removeFileHash: keeps the anchored regex, because Vite 8 content hashes are base64url and can contain-.setup()workaround came in with feat(bolt-vite-react-ts): upgrade to vite 7 #134 and are unchanged here.bolt-*templates:bolt-slidesis already on Vite 8.bolt-expo(Metro) andbolt-remotion(Webpack) don't use Vite.bolt-qwikstays on Vite 5, because Qwik 1.x declaresvite: ">=5 <8".viteis bumped later androlldownmoves off 1.2.16, the binding pin has to move with it. Rolldown checks the binding version matches.Performance in WebContainer
Same harness as #134:
@webcontainer/testwith Vitest browser mode, headless Chromium, Apple Silicon, Nov 3 2026. A fresh Chromium and a fresh WebContainer per run, 4 runs per version, alternating order, medians with min-max.npm installnpm run devto styled first rendernpm run build(wall clock)The runtime download is gone. With the binding pinned, 0 of 4 runs logged
Downloading @rolldown/binding-wasm32-wasi, and nopnpminvocation appears in the dev output. A control run with the devDependency removed logs the download and takes 7.16s to reach server-ready; with it, 1.52s.What is left. Vite 8 is about 1s slower than Vite 7 to a cold styled render and about 1.2s slower on a dev server restart, even with no download. That is Rolldown and Oxc running as WASM plus Lightning CSS. HMR is at parity and
vite build's own timer is faster by about 80ms, but wall-clock build time is about the same. Before this change the same measurement was 7.4s to server-ready and 8.9s to a styled render, so the pin recovers roughly 6s of the gap and leaves about 1s.Where the numbers come from. "Styled first render" is a Playwright wait inside the preview iframe until the starter text is present and Tailwind's
bg-gray-100is the computed background. For the download check I spawnednpm run devdirectly and matched the dev output. The negative control used the identical script with only the devDependency removed, which is how I know the check detects a download rather than passing vacuously.Test plan
npm ci,npm run build,npm run typecheck,tsc --noEmit -p tsconfig.node.json,npm run lint, andnpm run package:checkinbolt-vite-react-tstest/bolt-vite-react-ts.test.tsin Chromium: production build, and the dev preview renders and updates on editTestworkflow green (7 files / 14 tests). The first run failed onangularandbolt-exponpm installhook timeouts; a rerun passed those and all others.bolt-vite-react-tspassed on both runs.@rolldown/binding-wasm32-wasidownload on install or on first dev start, verified against a control run