Build tooling: updated OCaml bootstrapper, compile-modules, bundle.sh, sx-build-all. WASM browser: rebuilt sx_browser.bc.js/wasm, sx-platform-2.js, .sxbc bytecode files. CSSX/Tailwind: reworked cssx.sx templates and tw-layout, added tw-type support. Content: refreshed essays, plans, geography, reactive islands, docs, demos, handlers. New tools: bisect_sxbc.sh, test-spa.js, render-trace.sx, morph playwright spec. Tests: added test-match.sx, test-examples.sx, updated test-tw.sx and web tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
68 lines
5.1 KiB
Plaintext
68 lines
5.1 KiB
Plaintext
;; Async IO demo — Phase 5 client-side rendering with IO primitives.
|
|
;;
|
|
;; This component calls `highlight` inline — an IO primitive that runs
|
|
;; server-side Python. When rendered on the server, it executes
|
|
;; synchronously. When rendered client-side, the async renderer proxies
|
|
;; the call via /sx/io/highlight and awaits the result.
|
|
;;
|
|
;; `highlight` returns SxExpr — SX source with colored spans — which the
|
|
;; evaluator renders as DOM. The same SxExpr flows through the IO proxy:
|
|
;; server serializes → client parses → async renderer renders to DOM.
|
|
;;
|
|
;; Open browser console and look for:
|
|
;; "sx:route client+async" — async render with IO proxy
|
|
;; "sx:io registered N proxied primitives" — IO proxy initialization
|
|
|
|
(defcomp ~async-io-demo/content ()
|
|
(div (~tw :tokens "space-y-8")
|
|
(div (~tw :tokens "border-b border-stone-200 pb-6")
|
|
(h1 (~tw :tokens "text-2xl font-bold text-stone-900") "Async IO Demo")
|
|
(p (~tw :tokens "mt-2 text-stone-600")
|
|
"This page calls " (code (~tw :tokens "bg-stone-100 px-1 rounded text-violet-700") "highlight")
|
|
" inline — an IO primitive that returns SX source with colored spans. "
|
|
"On the server it runs Python directly. On the client it proxies via "
|
|
(code (~tw :tokens "bg-stone-100 px-1 rounded text-violet-700") "/sx/io/highlight")
|
|
" and the async renderer awaits the result."))
|
|
|
|
;; Live syntax-highlighted code blocks — each is an IO call
|
|
(div (~tw :tokens "space-y-6")
|
|
(h2 (~tw :tokens "text-lg font-semibold text-stone-800") "Live IO: syntax highlighting")
|
|
|
|
(div (~tw :tokens "rounded-lg border border-stone-200 bg-white p-5 space-y-3")
|
|
(h3 (~tw :tokens "text-sm font-medium text-stone-500 uppercase tracking-wide") "SX component definition")
|
|
(~docs/code :src
|
|
(highlight "(defcomp ~async-io-demo/card (&key title subtitle &rest children)\n (div :class \"border rounded-lg p-4 shadow-sm\"\n (h2 :class \"text-lg font-bold\" title)\n (when subtitle\n (p :class \"text-stone-500 text-sm\" subtitle))\n (div :class \"mt-3\" children)))" "lisp")))
|
|
|
|
(div (~tw :tokens "rounded-lg border border-stone-200 bg-white p-5 space-y-3")
|
|
(h3 (~tw :tokens "text-sm font-medium text-stone-500 uppercase tracking-wide") "Python server code")
|
|
(~docs/code :src
|
|
(highlight "from shared.sx.pages import mount_io_endpoint\n\n# The IO proxy serves any allowed primitive:\n# GET /sx/io/highlight?_arg0=code&_arg1=lisp\nasync def io_proxy(name):\n result = await execute_io(name, args, kwargs, ctx)\n return serialize(result)" "python")))
|
|
|
|
(div (~tw :tokens "rounded-lg border border-stone-200 bg-white p-5 space-y-3")
|
|
(h3 (~tw :tokens "text-sm font-medium text-stone-500 uppercase tracking-wide") "SX async rendering spec")
|
|
(~docs/code :src
|
|
(highlight ";; try-client-route reads io-deps from page registry\n(let ((io-deps (get match \"io-deps\"))\n (has-io (and io-deps (not (empty? io-deps)))))\n ;; Register IO deps as proxied primitives on demand\n (when has-io (register-io-deps io-deps))\n (if has-io\n ;; Async render: IO primitives proxied via /sx/io/<name>\n (do\n (try-async-eval-content content-src env\n (fn (rendered)\n (when rendered\n (swap-rendered-content target rendered pathname))))\n true)\n ;; Sync render: pure components, no IO\n (let ((rendered (try-eval-content content-src env)))\n (swap-rendered-content target rendered pathname))))" "lisp"))))
|
|
|
|
;; Architecture explanation
|
|
(div (~tw :tokens "rounded-lg border border-blue-200 bg-blue-50 p-5 space-y-3")
|
|
(h2 (~tw :tokens "text-lg font-semibold text-blue-900") "How it works")
|
|
(ol (~tw :tokens "list-decimal list-inside text-blue-800 space-y-2 text-sm")
|
|
(li "Server renders the page — " (code "highlight") " runs Python directly")
|
|
(li "Client receives component definitions including " (code "~async-io-demo/content"))
|
|
(li "On client navigation, " (code "io-deps") " list routes to async renderer")
|
|
(li (code "register-io-deps") " ensures each IO name is proxied via " (code "registerProxiedIo"))
|
|
(li "Proxied call: " (code "fetch(\"/sx/io/highlight?_arg0=...&_arg1=lisp\")"))
|
|
(li "Server runs highlight, returns SX source (colored span elements)")
|
|
(li "Client parses SX → AST, async renderer recursively renders to DOM")))
|
|
|
|
;; Verification instructions
|
|
(div (~tw :tokens "rounded-lg border border-amber-200 bg-amber-50 p-4 text-sm space-y-2")
|
|
(p (~tw :tokens "font-semibold text-amber-800") "How to verify async IO rendering")
|
|
(ol (~tw :tokens "list-decimal list-inside text-amber-700 space-y-1")
|
|
(li "Open the browser console (F12)")
|
|
(li "Navigate to another page (e.g. Data Test)")
|
|
(li "Click back to this page")
|
|
(li "Look for: " (code (~tw :tokens "bg-amber-100 px-1 rounded") "sx:route client+async /isomorphism/async-io"))
|
|
(li "The code blocks should render identically — same syntax highlighting")
|
|
(li "Check Network tab: you'll see 3 requests to " (code (~tw :tokens "bg-amber-100 px-1 rounded") "/sx/io/highlight"))))))
|