@xmachines/play-svelte-spa-router-demo
Examples / @xmachines/play-svelte-spa-router-demo
Svelte 5 + svelte-spa-router integration demo for the XMachines Play architecture using hash-based URL routing.
What This Demonstrates
- Shared auth machine reused without framework-specific business logic
connectRouterhash-URL ↔ actor sync via@xmachines/play-svelte-spa-router- Shell-driven rendering via
PlayRendererwith actor-authoritative navigation - Canonical TC39 Signals lifecycle integrated with Svelte 5 runes
- Non-browser invariant tests plus browser E2E coverage
Running the Demo
From the repository root:
npm installnpm run dev -w @xmachines/play-svelte-spa-router-demoThen open http://localhost:3005.
Step-by-Step Code Flow
Use this order to understand the implementation:
src/main.tsmountsApp.svelteand registers HMR cleanup viacleanup.src/runtime.tscreates the actor, builds the registry, callscreateRouteMap(authMachine), and wiresconnectRouter({ actor, routeMap }).connectRoutersynchronizes hash URL changes with the actor viaplay.routeevents and reflects actor-approved routes back to the hash URL.src/App.svelteimports the singletonactorandregistryResultfromsrc/runtime.tsand delegates to the sharedShell.svelte.Shell.svelterenders<PlayUIProvider>+<PlayRenderer />with the actor and registryResult and provides the shared UI shell (nav, debug panel).- Browser tests in
test/browser/validate startup and auth route transitions.
// src/runtime.ts (shape)const createDemoPlayer = definePlayer({ machine: authMachine });export const actor = createDemoPlayer();actor.start();
export const routeMap = createRouteMap(authMachine);export const disconnectRouter = connectRouter({ actor, routeMap });
export function cleanup(): void { disconnectRouter(); actor.stop();}<!-- src/App.svelte (shape) --><script lang="ts"> import { Shell } from "@xmachines/play-svelte-demo"; import { actor, registryResult } from "./runtime.js";</script>
<Shell {actor} {registryResult} /><!-- Shell.svelte — rendering (shape) --><PlayUIProvider actor={props.actor} registryResult={props.registryResult}> <PlayRenderer /></PlayUIProvider>Key Files
src/main.ts- Svelte app mount and HMR cleanup registrationsrc/runtime.ts- actor creation, registry construction, route map, andconnectRouterwiringsrc/App.svelte- minimal root component delegating to sharedShell.sveltetest/library-pattern.test.ts- architecture boundary and invariant assertionstest/browser/shared-demo.browser.test.ts- browser startup and auth route flow coverage
State Machine & Architecture Details
The demo utilizes XMachines architectural invariants:
- Actor Authority: When a user clicks a nav link, the hash URL changes.
connectRouterintercepts this, translates it to aplay.routeevent, and sends it to the actor. The actor evaluates guards (e.g.isAuthenticated) and transitions to the appropriate state. - Passive Infrastructure:
svelte-spa-routerdoes not execute business logic. The actor dictates whether navigation is permitted. The Svelte application only renders the state. - Signal-Only Reactivity: The bridge leverages Svelte 5 rune reactivity internally to react precisely when actor signals update, without ad-hoc
$statestores for business logic.
Watcher Lifecycle and Cleanup Contract
This demo follows the canonical watcher lifecycle used across all @xmachines framework adapters:
notifyqueueMicrotaskgetPending()- Read actor signals and project Svelte-local render state
- Re-arm with
watch()/watch(...signals)
Watcher notifications are one-shot. Cleanup is explicit: cleanup() calls disconnectRouter() and actor.stop() during HMR disposal, preventing memory leaks and ghost subscriptions.
Adapter Boundaries
connectRouter (from @xmachines/play-svelte-spa-router) is passive infrastructure. It translates hash URL changes into play.route events and reflects actor-approved route changes back to the URL. Business validity remains actor-owned. The shared Shell.svelte from @xmachines/play-svelte-demo is reused to avoid duplicating view components across router demos.
Available Scripts
These commands are defined in package.json:
| Command | Description |
|---|---|
npm run dev -w @xmachines/play-svelte-spa-router-demo | Start Vite dev server |
npm run build -w @xmachines/play-svelte-spa-router-demo | Build production bundle |
npm run preview -w @xmachines/play-svelte-spa-router-demo | Preview built bundle |
npm run test -w @xmachines/play-svelte-spa-router-demo | Run Vitest test suite |
npm run test:browser -w @xmachines/play-svelte-spa-router-demo | Run browser-focused Vitest suite |
Verification
Use these checks to validate README claims against the current demo implementation:
npm run test -w @xmachines/play-svelte-spa-router-demonpm run test:browser -w @xmachines/play-svelte-spa-router-demoExpected result: library-pattern invariant tests pass and the browser demo suite validates startup rendering and auth navigation.