Content & Discovery Layer — RSS, Search, Blogroll
Built the site's content discovery infrastructure: dual RSS feeds (blog + notes), Pagefind client-side search with post-build indexing, and a static blogroll with live descriptions fetched at build time.
RSS feeds
Two feeds, intentionally separate:
/rss.xml — blog posts only. This is the primary feed — durable content, longer-form writing, the kind of thing feed readers want. Listed in RSS autodiscovery <link> in the page <head> so any RSS reader can find it automatically.
/notes-rss.xml — notes only. Notes are shorter observations, links, quick thoughts. Separate feed lets people subscribe to just that signal if they want. Many don’t.
The reasoning for the split: blog posts and notes have different publishing frequencies and different expectations from subscribers. Mixing them into one feed means blog readers get spammed with quick observations and note-subscribers miss the signal in longer posts.
RSS autodiscovery is added to Layout.astro so every page on the site points readers (and feed readers) to both feeds.
Pagefind — client-side search without the weight
Pagefind generates a search index at build time as a CLI step after astro build. The index is sharded into small binary files — only the shards relevant to a query are loaded, not the full index on page load. On a site this size, that’s typically a 20–40KB transfer per search, total, versus Fuse.js which loads a full JSON dump of every page’s content.
The tradeoff comparison:
| Pagefind | Fuse.js | |
|---|---|---|
| Index size on load | Sharded, load on query | Full JSON on page load |
| Build step required | Yes (CLI after build) | No |
| Accuracy | Good, weighted | Good, fuzzy |
| CDN dependency | None | None if self-hosted |
| Offline support | Yes | Yes |
Setup: data-pagefind-body on <main> scopes the index to page content, excluding nav, footer, and the CrawlWidget. Individual pages can opt out entirely with a noindex Layout prop (crawl logs, 404, privacy).
Blogroll with live descriptions
The blogroll at /blogroll/ lists sites I read regularly. Each entry shows the site’s meta description, fetched from its homepage at build time using fetch() in Astro’s component script. The fetch happens once per build, the result is baked into the HTML — no runtime requests, no latency on page load.
The list is managed in Keystatic as a singleton with URL and optional fallback description fields. When a site doesn’t expose a usable meta description, the fallback is used instead.
Why static: Fetching descriptions at runtime would add external HTTP requests to every page load, with unpredictable latency and potential failures. Fetching at build time means the page always has a description (even if a site is temporarily down) and there’s zero runtime cost.
Feed icon in nav and footer
The RSS/feed icon appears in the nav alongside search, and in the footer social cluster alongside LinkedIn, GitHub, and X. On the homepage it’s also in the social strip. The icon is an inline SVG — the standard RSS broadcast symbol — no external image request.