Home /

Making the Site Smaller and Less Generic

How this site changed architecturally: inline CSS, cleaner output, richer post metadata, generated feeds, and page-size audits.

  • The site moved from Pico/Sass output to a small hand-written stylesheet that is inlined at build time.
  • Post frontmatter now drives canonical metadata, feeds, topic pages, JSON-LD, and agent-readable indexes.
  • The build now audits page-size budgets, broken links, draft exclusion, metadata, and output hygiene.

The first version of this site was static, but it was not as small or as explicit as it could be. I wrote about that original Go static-site stack in Building a Blog That Just Works; this is the pass that made the architecture match the constraint more closely.

It already avoided the expensive parts: no production JavaScript, no database, no client-side rendering, no analytics. The weaker parts were lower down in the stack. A small page still depended on framework CSS. The build copied files it did not need. Post metadata was too thin to power good previews, feeds, topic pages, or machine-readable indexes from one source of truth.

The rebuild tightened those edges. The page should arrive quickly, the generated output should contain only useful files, and the same post model should serve readers, search engines, feed readers, and agents.

Inline CSS

The first version used Pico through Sass. That kept the templates simple, but it produced a large stylesheet for a site with very few components.

I replaced it with a hand-written stylesheet in static/css/theme.css. The build minifies that CSS and inlines it into each HTML page. There is no production stylesheet request, no Sass build step, and no theme.min.css artifact in dist/.

Current measured sizes after the change:

homepage gzip: 2543 bytes
existing post gzip: 4767 bytes
theme source: 5780 bytes

That keeps the current pages well below the 12.5KB compressed first-response budget I added to go run . audit. The budget came from the same idea as the 14KB first response argument: make the useful page arrive early instead of waiting on extra render-blocking work.

Cleaner Output

The old build left too much behind for a tiny static site. Sass source, minified theme files, and unused assets could end up in the output tree even though the browser did not need them.

The build now treats dist/ as a generated artifact with a stricter contract:

  • remove the old output before rebuilding
  • inline the site stylesheet instead of copying it
  • skip .scss, .min.css, and the source theme file
  • write markdown alternates only for published posts
  • keep drafts out of production pages, feeds, sitemaps, and indexes

That makes production output easier to inspect. If a file is in dist/, it should either be a page, a feed, an index, or an asset the browser can actually request.

Metadata as Data

Posts now carry more metadata in frontmatter:

description: "..."
tags:
  - static-sites
key_points:
  - "..."
sources:
  - "https://example.com"

The build uses that data in several places:

  • HTML meta descriptions and canonical URLs
  • Open Graph and article metadata
  • compact BlogPosting JSON-LD from Schema.org
  • tag archive pages
  • feed.xml and JSON Feed
  • /posts.json, /llms.txt, and /llms-full.txt

The important part is not any single metadata format. It is that the metadata lives with the post. A better description improves the HTML snippet, feed item, JSON index, and structured data together. A tag creates a topic archive and gives related posts something concrete to share.

Agent Indexes

The site now generates a few small files for non-browser readers:

  • /posts.json for a compact list of published posts
  • /llms.txt for a short map of the site
  • /llms-full.txt for a fuller text index
  • /posts/<slug>/index.md for markdown alternates

These files are generated from the same parsed posts as the HTML pages. That keeps the agent-facing output boring in a good way: stable URLs, plain text, no hidden JavaScript state, and no separate content database to drift out of sync.

The llms.txt proposal is still young, so I do not want to overfit the site around it. Generating the file costs little, and the main rule is simple: if an agent asks what is here, give it a concise answer without making the human page worse.

Audit as a Build Contract

go run . audit now checks the things I do not want to rediscover manually:

  • compressed page-size budgets
  • exactly one <h1> per HTML page
  • required post metadata
  • draft exclusion from production output
  • broken internal links
  • generated agent files
  • build-output hygiene

The current rule is that architecture has to earn its place. No production JavaScript unless a page genuinely needs it. No framework stylesheet for a handful of components. No machine-facing file that cannot be generated from the post model. No output artifact that the build cannot explain.

The next weakness will probably show up once the archive is large enough to need navigation, search, or stronger related-post logic. Until then, the site should stay small and explicit.