docs: Phase 3 complete — toStream, prefetch, lazy routes, devtools, codemod

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014NgfSjHE11oFpoSnLVKLXd
This commit is contained in:
Bendik Aagaard Lynghaug
2026-09-08 18:57:51 +02:00
co-authored by Claude Fable 5
parent c101ee464a
commit ce8fedee0b
+28 -8
View File
@@ -31,9 +31,18 @@ everything new lives under `packages/`.
- `raw.js` — mark pre-encoded strings (works with both renderers)
- `packages/component``@choojs/component`: ← nanocomponent 6.6.0 +
on-load 3.4.1 as ES classes; the future island/hydration boundary.
- `packages/devtools``@choojs/devtools`: window.choo with live state,
event log, timings via PerformanceObserver, copy(); no-op on the server.
- `packages/migrate``@choojs/migrate`: the `choo-migrate` codemod.
Regex-based on purpose: converts simple top-level CJS to ESM, remaps
specifiers (choo → @choojs/core, nanohtml → @choojs/html, …), points
retired packages at their replacements, and reports everything it
refuses to guess at.
- `examples/counter` — the isomorphic proof: one app module, mounted
zero-build in the browser via import map (`index.html`), string-rendered
in Node (`render.js`).
- `examples/streaming` — streaming SSR demo server
(`node examples/streaming/server.js`).
## Status vs the modernization plan
@@ -59,14 +68,25 @@ apps by @choojs/component caching (proxy nodes skip unchanged subtrees),
and the number to beat if Phase 3 explores keyed-hole optimizations.
Server string rendering is on par with nanohtml v1 (~13k ops/s, within
6%). happy-dom numbers in bench/render.js are indicative only.
- [ ] Phase 3: v8 wiring (`toStream`, devtools, codemod). Includes the
answer to choojs/choo#653 (async/lazy routes): route handlers may
resolve lazily via native import(); browser renders previous tree
or a loading view until resolution, server awaits inside toStream
(toString stays sync and fails loudly). Deliberately deferred until
toStream exists so the SSR half ships with the browser half — the
missing server story is what stalled #653. API shape (thenable
handler vs lazy() wrapper vs loader-view option) goes to the RFC.
- [x] Phase 3: v8 wiring, all shipped together:
- `toStream(location, state)` — web-standard ReadableStream of
UTF-8; `new Response(stream)` on web servers,
`Readable.fromWeb(stream).pipe(res)` on Node. Progressive: the
server tag now builds a parts list, so promises/async iterables
in child position flush the shell first and stream the rest in
document order (proven byte-level and in real Chromium).
- `state.prefetch` — stores push promises during init; toStream
awaits them before rendering; toString refuses them loudly.
- `lazy(loader, loadingView?)` — the answer to choojs/choo#653,
both halves at once: browser renders the loading view (or holds
the current tree) until the dynamic import lands, server awaits
it in toStream; toString fails with guidance. Views cache after
first load.
- `@choojs/devtools` and the `choo-migrate` codemod (validated by
migrating choo's own v7 example and running the result on v8).
- [ ] Phase 3 follow-ups for the RFC: API shape feedback on lazy()
(thenable handlers vs wrapper), serializing streamed state for
hydration of async holes (bankai v10 territory).
- [ ] Phase 4: bankai v10 (Vite 8/Rolldown shell, SSR middleware,
103 Early Hints, service worker, precompression)
- [ ] Phase 5: docs, examples, launch