unbuffered: the publishing pipeline
Executive abstract
This site deploys itself: a git push triggers a pipeline that validates every document
against a typed schema, compiles diagrams from code, generates a full-text search index,
and ships static HTML to a global edge network. There is no server and no database.
Measured on the first production build: 14 pages in 1.6 s, homepage 1.7 kB gzipped
over the wire, site-wide JavaScript 766 bytes gzipped (a theme toggle and a diagram
detector — nothing else).
Environmental constraints
- Publishing cadence beats polish. The pipeline must make a 10-line tip as cheap to ship as a 5,000-word case study, or the site dies of friction.
- Free-tier hosting only. No fixed costs; everything must fit Cloudflare Pages’ free plan and a private GitHub repo.
- The author is the only operator. Anything that can rot silently (broken frontmatter, dead internal links) must instead fail loudly at build time.
Architecture blueprint
flowchart LR
A[Markdown in editor] -->|git push main| B[GitHub]
B -->|webhook| C[Cloudflare Pages build]
subgraph C_[astro build]
direction TB
C1[Zod schema check<br/>every frontmatter] --> C2[remark: wikilinks + mermaid]
C2 --> C3[Shiki dual-theme<br/>highlighting]
C3 --> C4[Static HTML + RSS + sitemap]
C4 --> C5[Pagefind WASM<br/>search index]
end
C --> C_
C_ --> D[(Edge network<br/>300+ PoPs)]
D --> E[Reader]
Bottleneck engineering
Diagram rendering. Build-time Mermaid rendering (rehype-mermaid) needs a headless
browser in CI — a heavyweight dependency for a static site. Instead, a 20-line remark
plugin rewrites ```mermaid fences into <pre class="mermaid"> at build time,
and a page-level script dynamically imports the renderer only when such a block exists.
Pages without diagrams ship zero JavaScript; pages with diagrams pay the cost lazily,
after first paint.
Search without a search server. Full-text search is usually the excuse for a backend. Pagefind indexes the built HTML at compile time and serves a chunked WASM index as static files — the browser fetches only the index fragments matching the query prefix.
Decision lineage
- Framework, hosting, and styling decisions: ADR-001
Post-mortem honesty
- The unified stream on the homepage re-sorts every collection on each build — O(n log n) over all entries. Irrelevant at n < 10,000 documents; noted here so future me doesn’t pretend it was designed for scale it doesn’t have.
- Mermaid’s renderer is heavy when it does load: a ~660 kB core chunk plus per-diagram-type
chunks (measured in
dist/_astro/). Vite code-splits it so non-diagram pages never fetch a byte of it, but diagram pages pay real weight after first paint. The right long-term fix is build-time SVG rendering; the current trade favors CI simplicity while diagram pages are rare.