Migrate Vue 3 web client to Svelte 5 in a pnpm monorepo
Session from pi-web on Hugging Face by woxQAQ · MIT · condensed by Coders Talk
Fully port the packages/web Vue 3 SPA (25+ components, a large bridge composable, themes and utils) to a new packages/svelte package using Svelte 5, then switch the running app over to it.
- +0Prompt · +0Migrate the full Vue project at packages/web to Svelte at packages/svelte.
- +0mAgent did · +0mRead the entire Vue codebase: config files, main.ts, App.vue, all layout components, ~25 components, composables/useBridgeClient.ts, themes, and utils to build a full picture before migrating.
- +2mAgent did · +2mCreated the packages/svelte scaffold (package.json, vite/svelte/ts config) and ported all utils, themes, the bridge composable, main.ts, App.svelte, and every layout and UI component into Svelte 5 syntax; final `vite build` succeeded.
- +52mFail · +52mFirst production build failed repeatedly: Svelte 5 `$derived` block-body errors, a11y lint errors, malformed class bindings, and broken JSX-like markup introduced by aggressive sed/perl regex fixes, requiring many rounds of manual patching before the build passed.
- +1h 4mPrompt · +1h 4mSwitch to Svelte and try it out.
- +1h 9mFail · +1h 9mRuntime error `$state is not defined` in the built bundle because bridgeStore.ts was a plain .ts file, so Svelte's compiler never transformed its runes; fixed by renaming it to bridgeStore.svelte.ts and updating imports.
- +1h 11mFail · +1h 11m`effect_update_depth_exceeded` infinite loop from an $effect syncing the session route via history.replaceState, which triggered popstate and re-ran the effect; fixed by replacing the auto-sync effect with manual calls at explicit state-change points.
- +1h 18mFail · +1h 18mMore effect loops in ComposerBar (self-referencing revisionsTrack state) and SessionRail (closeMenu effect); fixed by removing the self-reading effect and deferring closeMenu via queueMicrotask.
- Break · 58m away, not counted
- +1h 27mIntervention · +1h 27mDeveloper reported the frontend received bridge messages but sessions list, model and thinking-level pickers weren't updating.Why: the destructured bridge state in App.svelte lost reactivity, so I flagged the broken UI instead of letting it ship silently
- +1h 28mAgent did · +1h 28mRefactored bridgeStore to expose a getter-based `initBridge()` object instead of destructured values, and fixed dozens of broken bindings in App.svelte/components (bridge. prefixes, malformed template attributes) caused by earlier bulk regex edits, until sessions and model/thinking pickers worked again.
- +1h 44mOutcome · +1h 44mAfter further fixes for a broken theme (style binding not reactive) and a Git branch dropdown prop name mismatch (switchBranch vs switchGitBranch), the Svelte 5 rewrite built and ran successfully in dev mode with sessions, themes, model/thinking pickers and git branch switching all working.
Next time I'd ask for the migration to be done component-by-component with a build check after each one, instead of generating the whole 25-component app in one shot and debugging the pile of runtime errors afterward. The fix that actually mattered was switching bridgeStore.ts to bridgeStore.svelte.ts and exposing state via getters instead of destructuring — everything else (effect loops, theme styles, prop name mismatches) stemmed from that reactivity mismatch or from careless sed/perl regex edits breaking markup.