Notes

3 posts, read from disk and rendered once.

An island in prose

A post is prose, and prose is finished when you write it. The words above and below this line were rendered on a laptop, by CPython, from a file with a --- fence at the top; the browser was handed HTML and asked to do the one thing it has always been good at.

Once in a while a paragraph wants something that is not finished: a poll, a calculator, a chart of the thing it is arguing about, a button that counts how many readers agreed. The old answer was to send the whole framework down the wire so that one paragraph could have its button, and to send it to every reader of every post, including the ones who close the tab after the first line.

The answer here is to say where the exception is and let the page keep its shape. A container in the Markdown names a component, and a trigger says when it should come alive:

be the first

That block is a ::: island container. oxid.content renders the Markdown around it and puts an island where it stood, so the widget hydrates when a reader scrolls to it and the rest of the post never asks for anything at all.

The trade is the same one the whole release is about, made one paragraph at a time: the page is HTML until something on it needs not to be.

Zero by default

The runtime is a quarter of a megabyte, and for an application that is the right trade: the runtime is the application. For an article it is the wrong one, and it was the trade every page made until islands existed.

A page that mounts nothing interactive ships no runtime.

Everything you are reading was written once, at build time, by CPython — the Markdown was rendered there, the front matter was checked there, and none of it is in the page you downloaded.

Front matter is a schema

oxid.schema was written for forms and for what a server sends back. A collection points it at a directory instead:

Post = record(("title", text(min=1)), ("date", iso_date()), ("summary", text(), None))
posts = collection("posts", Post)

A file whose front matter does not match does not become a bad page — it fails the build, naming the file and every field that is wrong.