The browser example compiles one set of Haskell endpoint declarations for a
native Spock server and GHC’s JavaScript backend. Its browser UI creates,
replaces, appends, reloads and deletes a session note using typed Fetch calls.
Another endpoint exercises Unicode paths, .json extensions, optional and
repeated query parameters, and typed headers.
Start with the runnable example and build/deployment guide. It includes a checksummed compiler installer, separate Cabal projects, a local development loop, a complete deployable asset directory and real Chromium tests. Native code uses GHC 9.14.1; the pinned JavaScript cross compiler is 9.12.2 with Emscripten 3.1.74. The historical separate GHCJS/Stack setup has been replaced.
The three packages are deliberately small:
- Shared defines endpoint methods, paths and JSON types once.
- Server registers handlers and explicitly validates CSRF tokens for unsafe API routes.
- Client calls those declarations and renders responses using DOM
textContent.
The versioned API reference includes
callEndpoint,
callDocumentedEndpoint
and browserClient.
These pages are generated from the JavaScript build, including its browser-only module.
The client accepts configurable URL prefixes, credentials, timeouts and response
limits. It returns typed Either ClientError results for network, status, size
and decoding failures. Read the client API and migration guide
before adapting it to an existing application. Custom shared parameter types
need both FromHttpApiData and ToHttpApiData instances with Spock-api 0.17.
For production, serve the native executable and matching static assets behind TLS on the same origin. The demo’s in-memory notes disappear on restart; select a persistent backend and database when the application needs durable data. The browser security guide explains cookie and CSRF setup.
Client-side routing
Spock-browser
adds a typed navigation registry and a History API adapter. The demo uses
route, <//>, var and renderPath for Home, About and a note path containing
Unicode and an encoded slash. The browser changes its view without reloading
the document and handles back/forward, query strings and fragments.
mountRouter
owns links inside a configured path prefix; external links, downloads, modified
clicks, alternate targets and same-page fragment links keep their normal browser
behavior. Unknown paths invoke the application’s not-found handler. Call
unmountRouter
when removing the owning component to detach listeners and release callbacks.
Serve the application shell for GET deep links under the same prefix. The
example reserves /app/ for that fallback, so refreshing a typed route works
and missing /api/ routes still return 404. API authorization remains on the
server. The demo’s Chromium tests exercise navigation, reloads, native link
behavior and cleanup across repeated mounts.