Skip to content

serve: port serve-web from Vite to Rsbuild - #1009

Merged
bpowers merged 1 commit into
mainfrom
serve-web-rsbuild
Aug 2, 2026
Merged

bpowers merged 1 commit into
mainfrom
serve-web-rsbuild

Conversation

@bpowers

@bpowers bpowers commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Fixes #901

Ports src/simlin-serve/web from Vite to Rsbuild, removing the monorepo's second bundler (vite, @vitejs/plugin-react, vite-plugin-wasm, vite-plugin-top-level-await all drop out of the lockfile).

Design notes

  • output.assetPrefix: './' preserves Vite's base: './' so the SPA stays relocatable under any mount path (the Rust binary embeds it at /; a proxy can mount it elsewhere).
  • The flat distPath layout is load-bearing for that relative prefix, not cosmetic: Rspack builds runtime asset URLs as publicPath + <output-relative path>, resolved against the referencing context's base URL — the document on the main thread, but the worker script's own URL inside the engine's Web Worker. Nesting chunks under static/js/ would make the worker resolve the WASM blob to static/js/static/wasm/.... Putting every chunk at the dist root mirrors the flat assets/ directory Vite emitted, and is documented in the config.
  • experiments.asyncWebAssembly (same setup as src/app's rsbuild config) handles @simlin/engine's ESM-integration wasm import natively, replacing both Vite plugins.
  • A local globals.d.ts declare module '*.css' replaces the declaration vite/client used to provide (mirrors src/app/globals.d.ts).
  • @simlin/engine's webpack-vs-vite bundler-detection branches are untouched — they exist for external consumers of the published package (out of scope per the issue).
  • build: no dist-level smoke check that @simlin/diagram CSS (theme.css/reset.css) lands in serve-web bundle #828's proposed smoke check should now be written against this layout (dist/index.*.css at the root rather than dist/assets/index-*.css).

Verification

Beyond the unit/lint/tsc gates, verified against the rebuilt simlin-serve binary in a real browser, since worker/wasm resolution is exactly what unit tests can't see:

Also updates the now-stale Vite references: CI step comments, deploy-tooling comment lists, docs/dev/deploy.md, docs/tech-debt.md, and fixes the stale "React 19 + Vite + Jest" line in src/simlin-serve/CLAUDE.md.

serve-web was the last frontend in the monorepo building with Vite;
src/app builds with Rsbuild and website with Rspress, and serve-web's
tests already moved to Rstest during the Jest migration. Carrying the
second bundler meant a second dependency tree, a second set of
wasm/top-level-await workarounds, and divergent sideEffects/resolution
semantics at exactly the boundary where the diagram-CSS contract is
invisible to unit tests.

The Rsbuild config preserves Vite's 'base: ./' via output.assetPrefix
so the SPA stays relocatable under any mount path. The flat distPath
layout is load-bearing for that: Rspack builds runtime asset URLs as
publicPath + output-relative path resolved against the referencing
context (the worker script's own URL inside the engine's Web Worker),
so nesting chunks under static/js/ would make the worker resolve the
WASM blob to static/js/static/wasm/. rspack's asyncWebAssembly handles
the engine's ESM wasm import natively, replacing vite-plugin-wasm and
vite-plugin-top-level-await; a local globals.d.ts CSS-module
declaration replaces vite/client's.

Verified in-browser against the rebuilt serve binary: editor renders
teacup.xmile, the engine worker spawns, the simulation runs (sparkline
plus full series in variable details), theme tokens and katex CSS land
in the bundle, and the dist serves correctly from a subpath.

Also drops the now-stale vite mentions from the deploy tooling
comments and fixes the stale 'Vite + Jest' line in the serve
CLAUDE.md.
@codecov

codecov Bot commented Aug 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.86%. Comparing base (b92f8d1) to head (b6b9a99).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1009   +/-   ##
=======================================
  Coverage   91.86%   91.86%           
=======================================
  Files         247      247           
  Lines      159159   159159           
=======================================
+ Hits       146207   146210    +3     
+ Misses      12952    12949    -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@claude

claude Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review: serve: port serve-web from Vite to Rsbuild

Reviewed the bundler swap end-to-end (config, package manifest, tsconfig, index.html, tests, docs, and the rust-embed layout contract).

No blocking issues found. The change is well-scoped and the config comments are thorough:

  • assetPrefix: './' + the flat distPath correctly preserves the relative-URL relocatability property (the load-bearing detail called out in the comment, and it matches the sibling constraint in src/engine/src/engine-worker.ts about worker self.location resolution).
  • experiments.asyncWebAssembly + the .wasm rule is the same setup src/app/config/rsbuild/shared.config.js uses; it correctly replaces vite-plugin-wasm + vite-plugin-top-level-await for @simlin/engine's ESM-integration wasm import.
  • vite/client types are cleanly replaced by globals.d.ts (declare module '*.css'); grep confirms no import.meta.env / import.meta.hot usage in src/simlin-serve/web/src/, so the trimmed type surface is sufficient.
  • Removing the inline module script tag from index.html is correct since Rsbuild auto-injects from source.entry.index (mirrors the pattern in src/app/public/index.html).
  • Rsbuild's default filename pattern in production, combined with the flat distPath, produces dist/index.<hash>.{js,css} at the root -- consistent with the smoke-check assumption noted for the follow-up.
  • CI comment update, deploy-tooling comment lists, docs/dev/deploy.md, and docs/tech-debt.md are all consistently updated; src/simlin-serve/CLAUDE.md's stale "React 19 + Vite + Jest" line is fixed.

The author has manually verified worker/WASM resolution and subpath serving in a real browser -- the failure modes unit tests cannot see.

Overall correctness: correct

The patch should not break existing code or tests. No bugs identified.

@bpowers
bpowers merged commit ae7792f into main Aug 2, 2026
15 checks passed
@bpowers
bpowers deleted the serve-web-rsbuild branch August 2, 2026 13:50
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.

serve: simlin-serve/web builds with Vite while the rest of the repo builds with Rsbuild

1 participant