Skip to content

labs: the RSS feed works again, with one feed per product - #507

Open
sderossi wants to merge 1 commit into
mainfrom
fix/rss
Open

sderossi wants to merge 1 commit into
mainfrom
fix/rss

Conversation

@sderossi

@sderossi sderossi commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

https://labs.leaningtech.com/rss.xml returns 404. The endpoint exported get, and since the Astro upgrade only GET is called. The build warned about it: No API Route handler exists for the method "GET" for the route "/rss.xml".

What changes

  • /rss.xml works again. It's built by a shared helper (sites/labs/src/lib/feeds.ts) that leaves out drafts, sorts newest first and passes explicit fields: title (with subtitle), description, date, and tags and categories as <category>. The old code spread all of the frontmatter into each item, including the hero image object.
  • One feed per product: /rss/cheerpj.xml, /rss/cheerp.xml, /rss/cheerpx.xml, /rss/browserpod.xml, filtered by the post's tags.
  • Links without a trailing slash. @astrojs/rss adds one by default, but posts are built as blog/<slug>.html, so each feed link would have cost a redirect.
  • Feed readers can find the feeds. The blog index lists all five feeds as <link rel="alternate">, and each post lists the main feed plus its products' feeds. Shell.astro gets a named head slot for this. It's empty wherever it isn't used.

Checked locally

  • The labs site builds, astro check reports 0 errors, and Prettier passes.
  • All five feeds are valid XML. rss.xml has 51 items, rss/cheerpj.xml has 18.
  • All 106 item links point to pages that exist in dist/.
  • With the CheerpJ 5.0 post (Cj 5.0 post #491) copied in temporarily, it was the first item in rss.xml and rss/cheerpj.xml. It isn't part of this PR.

After deploy

  • https://labs.leaningtech.com/rss.xml and https://labs.leaningtech.com/rss/cheerpj.xml answer 200 with application/xml or application/rss+xml.
  • A feed reader pointed at https://labs.leaningtech.com/blog offers the five feeds.

🤖 Generated with Claude Code

/rss.xml has 404'd since the Astro upgrade: the endpoint exported `get`, and
Astro now only calls `GET`. The feed is rebuilt on a shared helper that skips
drafts, sorts newest first, and links to /blog/<slug> without the trailing
slash @astrojs/rss adds by default (posts are built as blog/<slug>.html).

Each product tag also gets its own feed at /rss/<product>.xml, so CheerpJ
users can follow /rss/cheerpj.xml. The blog index lists every feed, and each
post lists the main feed plus its products' feeds, as <link rel="alternate">
tags so feed readers find them. Shell gains a named "head" slot for that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sderossi sderossi self-assigned this Nov 2, 2026
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying labs-browserpod-previews with  Cloudflare Pages  Cloudflare Pages

Latest commit: f73dd9e
Status: ✅  Deploy successful!
Preview URL: https://e07f1fa5.labs-browserpod-previews.pages.dev
Branch Preview URL: https://fix-rss.labs-browserpod-previews.pages.dev

View logs

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying labs-cheerpj-previews with  Cloudflare Pages  Cloudflare Pages

Latest commit: f73dd9e
Status: ✅  Deploy successful!
Preview URL: https://982de613.labs-cheerpj-previews.pages.dev
Branch Preview URL: https://fix-rss.labs-cheerpj-previews.pages.dev

View logs

@sderossi
sderossi marked this pull request as ready for review November 2, 2026 16:38

@GabrielaReyna GabrielaReyna left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blockers and no bugs I can find, the suggestions below are polish:

  • Nobody can find the feeds yet. The <link rel="alternate"> tags work for bots, but browsers stopped surfacing them years ago, so a human on the blog page has no way to know a feed exists. A visible subscribe link in the filter row would fix it, the component already knows which product is selected.
  • Each feed should state its own address (<atom:link rel="self">). Costs one line, and it’s what keeps /rss/cheerp.xml and /rss/cheerpj.xml distinct once a bot picks them up second-hand.
  • An RSS icon in the footer, so the feed is reachable from any page and not just the blog. Fine as a follow-up change.
  • Category feeds can wait. The blog filters by product and category, but we only have product feeds. I’d rather check the /rss.xml access logs in a month before building more.

Others:
Minor: the item counts in the description look one off. I get 50 and 17, not 51 and 18.

description: product
? `Releases, technical deep dives and news about ${product} from the Leaning Technologies engineering blog.`
: SITE_DESCRIPTION,
site: context.site!,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we have five feeds instead of one, could we add a few bits of channel metadata? They’re what aggregators and feed readers look for, and they all go in the same rss() call.

Right now only the <link> tag exists, and it points at the site root. So if you open rss/cheerpj.xml today, nothing inside tells you you’re looking at the CheerpJ feed rather than the Cheerp one or the main one.
The fix is an <atom:link rel="self"> tag, which points at the feed file itself, so each feed states its own address. It matters when a feed gets copied, mirrored, or pulled through a proxy: the bot can still find its way back to the original. And it matters for us specifically, because five feeds in the same folder look very similar.This is what keeps /rss/cheerp.xml and /rss/cheerpj.xmlclearly distinct downstream.

Worth adding <language> and <lastBuildDate> while we’re in there too. lastBuildDate should be the newest post’s date rather than the build time, otherwise every deploy makes the feed look changed when nothing was added.

Comment on lines +58 to +68
{
[undefined, ...FEED_PRODUCTS].map((product) => (
<link
slot="head"
rel="alternate"
type="application/rss+xml"
title={feedTitle(product)}
href={feedPath(product)}
/>
))
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now the <link> tags are the only way to find these feeds, and Chrome and Safari stopped surfacing those years ago. So in practice a reader on this page has no way to discover we have a feed. Can we add a visible subscribe link?

: post.data.title,
description: post.data.description,
pubDate: post.data.pubDate,
link: `/blog/${post.slug}`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor heads up: dropping the trailing slash changes every item’s guid. Unsure if this hasn't been 404 forever, but if not it might notify 50 new posts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants