Solid Router Demo
Examples / @xmachines/play-solid-router-demo
Solid + @solidjs/router demonstration of the Play architecture using provider-based router integration.
What This Demonstrates
- Shared auth machine reused without framework-specific business logic
PlayRouterProviderrenderer-based integration with Solid Router- Shell-driven rendering via
PlayRendererwith actor-authoritative navigation - Canonical TC39 Signals lifecycle integration with Solid’s fine-grained reactivity
- Non-browser invariant tests plus browser E2E coverage
Running the Demo
From this directory (packages/play-solid-router/examples/demo):
npm installnpm run devOpen http://localhost:5173.
Step-by-Step Code Flow
Use this order to understand the implementation:
src/main.tsxbootstraps the demo and mounts the<App />component.src/App.tsxwires actor lifecycle, shared machine/catalog imports, and router integration.- A
routeMapis created by extracting routes from the sharedauthMachine. PlayRouterProviderforwards navigation intent from@solidjs/routerto the actor, and reflects actor-approved routes back to the URL.Shell(insidesrc/App.tsx) renders actor-projected views (PlayRenderer) and provides the shared UI shell.test/library-pattern.test.tsandtest/browser/verify invariants and runtime routing behavior.
// src/main.tsx (shape)render(() => <App />, document.getElementById("root")!);// src/App.tsx (shape)const createPlayer = definePlayer({ machine: authMachine, catalog });const actor = createPlayer();actor.start();
const routeMap = createRouteMap(authMachine);
<PlayRouterProvider actor={actor} routeMap={routeMap} router={{ navigate, location, params }} renderer={(currentActor, currentRouter) => ( <Shell actor={currentActor} router={currentRouter} /> )}/>;// src/components/Nav.tsx (shape)<button onClick={() => actor.send({ type: "auth.logout" })}>Logout</button>Key Files
src/App.tsx- Integration entry point wiring actor, provider, renderer, and shared machine/catalog imports.src/main.tsx- Vite bootstrap for the Solid app.src/components/- Demo views and controls that send events to the actor.test/library-pattern.test.ts- Node/Vitest invariant checks for architecture boundaries.test/browser/startup.browser.test.ts- Browser startup and mount coverage.test/browser/auth-flow.browser.test.ts- Browser auth and routing behavior coverage.
State Machine & Architecture Details
The demo utilizes XMachines architectural invariants:
- Actor Authority: When a user navigates to a protected route, the Solid Router updates the URL. The
PlayRouterProviderintercepts this, translates it to aplay.routeevent, and sends it to the actor. The actor evaluates guards (e.g., is the user logged in?) and transitions to the appropriate state. - Passive Infrastructure: Solid components hold no business state. They observe
actor.currentViewto know what to render, andactor.currentRouteto reflect the active path. - Signal-Only Reactivity: Instead of React-like re-renders, Solid uses
createEffectinternally within theRouterBridgeto react precisely when signals update.
Watcher Lifecycle and Cleanup Contract
This demo follows the canonical watcher lifecycle:
notifyqueueMicrotaskgetPending()- Read actor signals and update Solid-local render triggers
- Re-arm with
watch()/watch(...signals)
Watcher notifications are one-shot. Cleanup is explicit and lifecycle-bound: Solid teardown uses onCleanup, and provider/bridge teardown must call disconnect/unwatch paths rather than relying on GC-only cleanup. This is crucial to prevent memory leaks during component unmounting.
Adapter Boundaries
Solid Router integration remains passive infrastructure. RouterBridgeBase stays the shared policy point; the Solid adapter only implements framework port behavior (calling navigate() and tracking location.pathname).
Available Scripts
npm run dev # Start Vite dev server (default: http://localhost:5173)npm run build # Build production assetsnpm run preview # Preview production build locallynpm run test # Run unit/integration tests via Vitestnpm run test:browser # Run browser-mode tests via vitest.browser.config.tsVerification
Use these checks from this directory:
npm run testnpm run test:browserManual sanity check:
- Start the app with
npm run dev. - Open
http://localhost:5173. - Confirm login/logout transitions update both view and URL, and that accessing protected routes while logged out redirects properly.