Skip to content

Commit 58c28db

Browse files
committed
blog: publish an RSS feed
Six long essays and no way to subscribe: /rss.xml and /feed.xml both answered 404, so an aggregator had nothing to poll. Adds @astrojs/rss and a /rss.xml route, newest first — the reverse of the index, which reads oldest first the way a bibliography does. Items carry the excerpt rather than the body: the posts run to thousands of words with KaTeX and highlighted code, none of which survives a feed reader intact. Discovery goes in the head on every page; /blog also carries a visible link, since a reader who wants the feed should not have to view source. Claude-Session: https://claude.ai/code/session_01S3mVZMgbynFxc2N874K9nH
1 parent 45b26a8 commit 58c28db

5 files changed

Lines changed: 183 additions & 0 deletions

File tree

package-lock.json

Lines changed: 132 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
},
2020
"dependencies": {
2121
"@astrojs/mdx": "^7.0.8",
22+
"@astrojs/rss": "^4.0.19",
2223
"@astrojs/sitemap": "^3.7.3",
2324
"@resvg/resvg-js": "^2.6.2",
2425
"astro": "^7.2.9",

src/layouts/BaseLayout.astro

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ const fontHref =
4747
<link rel="manifest" href="/site.webmanifest" />
4848
<meta name="theme-color" content="#FCFCFA" />
4949
<link rel="sitemap" href="/sitemap-index.xml" />
50+
<link
51+
rel="alternate"
52+
type="application/rss+xml"
53+
title="Diego Said — Writing"
54+
href="/rss.xml"
55+
/>
5056

5157
{/* Open Graph */}
5258
<meta property="og:title" content={title} />

src/pages/blog/index.astro

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ const posts = (await getCollection('blog')).sort(
2020
<p class="mt-3 text-[17px] text-muted leading-relaxed">
2121
Long-form essays on protocol design, distributed systems, and AI infrastructure.
2222
</p>
23+
<a
24+
href="/rss.xml"
25+
class="inline-block mt-4 font-mono text-[13px] text-muted hover:text-accent transition-colors"
26+
>
27+
RSS
28+
</a>
2329
<div class="mt-12 border-t border-rule divide-y divide-rule">
2430
{
2531
posts.map((post) => (

src/pages/rss.xml.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import rss from '@astrojs/rss';
2+
import type { APIContext } from 'astro';
3+
import { getCollection } from 'astro:content';
4+
5+
/**
6+
* Feed for /blog.
7+
*
8+
* Newest first — the reverse of the index page, which reads oldest first the
9+
* way a bibliography does. A reader pulls the feed to see what is new.
10+
*
11+
* Items carry the excerpt, not the post body. The posts run to several thousand
12+
* words with KaTeX and highlighted code, none of which survives a feed reader
13+
* intact, so the description is the blurb and the link is the article.
14+
*/
15+
export async function GET(context: APIContext) {
16+
const posts = (await getCollection('blog')).sort(
17+
(a, b) => b.data.date.valueOf() - a.data.date.valueOf(),
18+
);
19+
20+
return rss({
21+
title: 'Diego Said — Writing',
22+
description:
23+
'Long-form essays on protocol design, distributed systems, and AI infrastructure.',
24+
// Set in astro.config; the type is nullable because a site-less config is
25+
// legal, so fall back rather than emit a feed full of relative links.
26+
site: context.site ?? 'https://diegosaid.com',
27+
items: posts.map((post) => ({
28+
title: post.data.title,
29+
description: post.data.excerpt,
30+
pubDate: post.data.date,
31+
categories: post.data.tags,
32+
// Trailing slash: Cloudflare Pages 308-redirects the bare form, and a
33+
// feed reader that follows the redirect would record a different id.
34+
link: `/blog/${post.id}/`,
35+
})),
36+
customData: '<language>en-us</language>',
37+
});
38+
}

0 commit comments

Comments
 (0)