README rewritten for the v8 branch: honest size claim (7.97 kB min+gzip for the whole framework, with the v7 '4kb' context), the zero-build story up front, bankai v10, package map, credits to yoshuawuyts, the choojs contributors and the pirxpilot fork line. docs/migrating-v7-to-v8.md: the codemod path, the specifier map, and every deliberate behavior change spelled out. docs/deploy.md: plain Node, Docker, proxy/CDN — including the HTTP/3 answer (h3 is infrastructure's job; bankai's contract is the 103 + Link headers that any hints-aware edge, h3 included, propagates; server push is dead everywhere and never existed in h3) — and web-standard runtimes. docs/rfc.md: the draft announcement for choojs/choo — continuation framing, pings to yoshuawuyts and pirxpilot, the npm-rights ask, API feedback questions, and a three-week comment window with a silence-is-consent close. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014NgfSjHE11oFpoSnLVKLXd
130 lines
4.8 KiB
Markdown
130 lines
4.8 KiB
Markdown
<h1 align="center">choo</h1>
|
|
|
|
<div align="center">
|
|
<strong>🚂🚋🚋🚋🚋🚋</strong>
|
|
</div>
|
|
<div align="center">
|
|
The sturdy frontend framework — now with a modern engine under the same hood.
|
|
</div>
|
|
|
|
<br>
|
|
|
|
> **This is the v8 branch.** choo v7 is on `master` and stays untouched
|
|
> until 8.0.0 ships. Everything below describes v8: same API, same
|
|
> philosophy, rebuilt for the platform of 2026. See
|
|
> [`docs/v8.md`](docs/v8.md) for status and the full plan.
|
|
|
|
## What is this
|
|
|
|
Choo is a small framework for building frontend applications with plain
|
|
JavaScript and HTML. State lives in stores, changes flow through an event
|
|
emitter, views are tagged template literals, and re-renders morph the real
|
|
DOM. The whole framework — core, html engine, morphing, hydration, router,
|
|
event bus — is **7.97 kB min+gzip** (7.15 kB brotli), enforced by CI.
|
|
|
|
```js
|
|
import choo from '@choojs/core'
|
|
import html from '@choojs/html'
|
|
|
|
const app = choo()
|
|
|
|
app.use((state, emitter) => {
|
|
state.count = 0
|
|
emitter.on('increment', (n) => {
|
|
state.count += n
|
|
emitter.emit('render')
|
|
})
|
|
})
|
|
|
|
app.route('/', (state, emit) => html`
|
|
<body>
|
|
<h1>count is ${state.count}</h1>
|
|
<button onclick=${() => emit('increment', 1)}>Increment</button>
|
|
</body>
|
|
`)
|
|
|
|
app.mount('body')
|
|
```
|
|
|
|
## Why v8
|
|
|
|
- **No build step, anywhere.** Templates parse at runtime (cached per
|
|
call site in a WeakMap, clone-based instantiation — as fast as the old
|
|
compile-time transform, without the toolchain). An import map and a
|
|
`<script type="module">` is a complete development setup:
|
|
see [`examples/counter/index.html`](examples/counter/index.html).
|
|
- **Isomorphic by contract.** One app module. The browser mounts it, the
|
|
server imports the same file and calls `toString(route)` or streams it
|
|
with `toStream(route)` — a web-standard `ReadableStream`, so it plugs
|
|
into Node, Deno, Bun, and edge runtimes alike.
|
|
- **Streaming SSR.** Async values in child position flush the shell
|
|
first and stream the rest in document order. Store data via
|
|
`state.prefetch` promises. Hydration *adopts* the server DOM (same
|
|
element references, form state kept) and warns precisely when server
|
|
and client markup disagree.
|
|
- **Async routes, finally.** `app.route('/big', lazy(() => import('./big.js')))`
|
|
— loading view or held tree while in flight, awaited on the server.
|
|
([choojs/choo#653](https://github.com/choojs/choo/pull/653), answered.)
|
|
- **Modern platform, no shims.** ESM only, Node ≥ 24, Baseline
|
|
Widely Available browsers. The router speaks WHATWG URL and survives
|
|
emoji, literal `%`, and Unicode normalization differences.
|
|
|
|
## bankai v10
|
|
|
|
The isomorphic compiler & server, rebuilt on Vite 8 / Rolldown. Only the
|
|
client ever bundles — v8 server code is plain ESM Node runs as-authored.
|
|
|
|
```console
|
|
$ bankai start app.js # dev: HMR + streaming SSR on every request
|
|
$ bankai build app.js # client bundle, manifest, service worker,
|
|
# brotli/gzip precompression, --prerender
|
|
$ bankai serve # prod: 103 Early Hints, immutable assets,
|
|
# streaming SSR, --h2
|
|
$ bankai inspect # raw/gzip/brotli size report
|
|
```
|
|
|
|
Conventions over config: `style.css` next to your entry is bundled for
|
|
the client (server code never sees it), `sw.js` becomes a service worker
|
|
with the precache manifest injected, `<title>` follows your
|
|
`DOMTitleChange` emits — on the server too.
|
|
|
|
## Packages
|
|
|
|
| package | what it is |
|
|
|---|---|
|
|
| `@choojs/core` | the Choo class: stores, router, emitter, `toString`/`toStream`, `lazy()` |
|
|
| `@choojs/html` | tagged templates: DOM in the browser, strings/streams on the server, `morph`, `hydrate`, `raw` |
|
|
| `@choojs/component` | stateful components with lifecycle hooks; the hydration boundary |
|
|
| `@choojs/devtools` | `window.choo` console tooling |
|
|
| `@choojs/migrate` | `choo-migrate` — the v7 → v8 codemod |
|
|
| `bankai` | the compiler & server above |
|
|
|
|
## Migrating from v7
|
|
|
|
```console
|
|
$ npx @choojs/migrate .
|
|
```
|
|
|
|
converts simple CJS, remaps every specifier, and tells you honestly what
|
|
it didn't dare touch. The API surface is unchanged — `choo()` still works
|
|
without `new`. See [`docs/migrating-v7-to-v8.md`](docs/migrating-v7-to-v8.md).
|
|
|
|
## Development
|
|
|
|
```console
|
|
$ npm install
|
|
$ npm test # 109 tests on node:test, zero framework deps
|
|
$ npm run test:e2e # real Chromium: hydration, streaming, bankai
|
|
$ npm run size # the wire-size budget
|
|
$ npm run bench # vs nanohtml v1 and µhtml
|
|
```
|
|
|
|
## Credits
|
|
|
|
Choo v8 carries forward a decade of work by
|
|
[Yoshua Wuyts](https://github.com/yoshuawuyts) and the
|
|
[choojs contributors](https://github.com/choojs), and builds on the
|
|
ESM groundwork of the [@pirxpilot](https://github.com/pirxpilot) fork
|
|
line. Per-file attribution headers name the module and version each port
|
|
came from. MIT, as always.
|