Files
buuh/README.md
T

164 lines
5.9 KiB
Markdown
Raw Normal View History

<h1 align="center">buuh</h1>
2016-05-10 23:23:33 +07:00
2016-05-25 04:28:20 +09:00
<div align="center">
<strong>🚂🚋🚋🚋🚋👻</strong>
2016-05-25 04:28:20 +09:00
</div>
<div align="center">
The sturdy little frontend framework — a friendly fork of choo,
rebuilt for the modern platform.
2016-05-25 04:28:20 +09:00
</div>
2016-05-13 12:49:22 +07:00
<br>
2016-05-10 23:23:33 +07:00
> **buuh is a fork of [choo](https://github.com/choojs/choo)** — same
> API, same philosophy, modern engine. It exists because we love choo
> and wanted it alive on today's platform; all credit for the design
> belongs upstream (see [Credits](#credits)). Everything is MIT, and if
> upstream ever wants this work home, the door is open
> ([`docs/upstream-rfc-draft.md`](docs/upstream-rfc-draft.md)).
2016-05-25 04:28:20 +09:00
## What is this
2016-05-25 04:28:20 +09:00
buuh 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.
2016-05-25 04:28:20 +09:00
2016-06-01 01:03:25 +02:00
```js
import choo from '@uhhm/buuh'
import html from '@uhhm/buuh-html'
2017-03-21 03:00:45 +01:00
const app = choo()
2016-06-01 01:03:25 +02:00
app.use((state, emitter) => {
2017-03-21 03:00:45 +01:00
state.count = 0
emitter.on('increment', (n) => {
state.count += n
2017-03-21 03:00:45 +01:00
emitter.emit('render')
})
2017-06-28 15:53:37 +02:00
})
app.route('/', (state, emit) => html`
2017-10-20 16:30:58 +02:00
<body>
<h1>count is ${state.count}</h1>
<button onclick=${() => emit('increment', 1)}>Increment</button>
2017-10-20 16:30:58 +02:00
</body>
`)
2017-10-20 16:30:58 +02:00
2018-07-10 14:40:51 +02:00
app.mount('body')
```
## Getting it
From the uhhm registry (one `.npmrc` line routes the scope; everything
else still resolves from npmjs):
```console
$ echo "@uhhm:registry=https://project.uhhm.no/api/packages/uhhm/npm/" >> .npmrc
$ npm i @uhhm/buuh @uhhm/buuh-html
$ npm i -D @uhhm/bankai
```
Or with no package manager at all — one file, one import map:
```html
<script type="importmap">
{ "imports": { "buuh": "https://cdn.uhhm.no/buuh@8.0.0.js" } }
</script>
<script type="module">
import { choo, html } from 'buuh'
</script>
```
See [`docs/publishing.md`](docs/publishing.md) for how the registry and
the CDN bundle fit together.
## Why this fork
2018-07-10 14:40:51 +02:00
- **No build step, anywhere.** Templates parse at runtime (cached per
call site in a WeakMap, clone-based instantiation — as fast as choo's
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.** `app.route('/big', lazy(() => import('./big.js')))`
— loading view or held tree while in flight, awaited on the server
(the answer to [choojs/choo#653](https://github.com/choojs/choo/pull/653)).
- **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.
2018-07-10 14:40:51 +02:00
## bankai
2016-05-19 13:26:11 +09:00
The isomorphic compiler & server, rebuilt on Vite 8 / Rolldown. Only the
client ever bundles — server code is plain ESM Node runs as-authored.
2016-07-05 18:52:51 +02:00
```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
2016-06-20 23:57:46 -04:00
```
2016-12-11 19:35:29 +01:00
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.
2017-06-28 15:53:37 +02:00
## Packages
| package | what it is |
|---|---|
| `@uhhm/buuh` | the app class: stores, router, emitter, `toString`/`toStream`, `lazy()` |
| `@uhhm/buuh-html` | tagged templates: DOM in the browser, strings/streams on the server, `morph`, `hydrate`, `raw` |
| `@uhhm/buuh-component` | stateful components with lifecycle hooks; the hydration boundary |
| `@uhhm/buuh-devtools` | `window.choo` console tooling |
| `@uhhm/buuh-migrate` | `buuh-migrate` — the choo v7 → buuh codemod |
| `@uhhm/bankai` | the compiler & server above (bin: `bankai`) |
## Migrating from choo v7
```console
$ npx @uhhm/buuh-migrate .
2017-06-28 15:53:37 +02:00
```
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).
2016-07-21 21:59:01 +02:00
## Development
2016-07-21 21:59:01 +02:00
```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
$ npm run bundle # the single-file CDN build
2016-05-24 22:11:21 +09:00
```
2016-05-11 15:26:27 +07:00
Releases: bump versions, `git tag vX.Y.Z`, push the tag — Gitea Actions
tests, publishes every package to the uhhm registry, and uploads the CDN
bundle ([`.gitea/workflows/release.yml`](.gitea/workflows/release.yml)).
## Credits
2016-05-22 02:15:33 +09:00
buuh is choo. The design, the API, and most of the ideas are
[Yoshua Wuyts](https://github.com/yoshuawuyts)'s and the
[choojs contributors](https://github.com/choojs)'; the ESM groundwork
came from the [@pirxpilot](https://github.com/pirxpilot) fork line; this
fork modernized the engine and the toolchain around them. Per-file
attribution headers name the module and version each port came from.
MIT, as always.