RSS feed with Tanstack Start
I have been slowly working at this site more since Tanstack Start has been in RC. This is my first time building with Tanstack Router, coming from a background primarily working on Nextjs with react query. Some conventions were slightly different along the way but mostly quite similar concepts.
Tanstack Start Docs
The Tanstack Start documentation are great and comes with an SEO guide that outlines how to create sitemaps.xml and robots.txt files statically and dynamically. I had no need to create a dynamic robots.txt for this site and opted to just use Tanstack's built-in sitemap generator. Reading the guide on the the dynamic robots.txt would have shown exactly what to do for the rss.xml file. The docs also recommend reading the Tanstack Router as they are coupled by design.
Generating a dynamic rss.xml file
Perquisites
This guide assumes you have a way to return all your posts/content and your tanstack start site is not statically deployed.
Server Route
Create a server route with the file src/routes/rss[.]xml.ts, this was not abundantly clear to me but is outlined in the File Name Conventions apart of the router documentation. Download the rss npm package with
pnpm install rss
or with whatever package manager you are using.
Then after configuring your posts you should end up with a file looking like
import { env } from '@/env'
import { createFileRoute } from '@tanstack/react-router'
import { allPosts } from 'content-collections'
import RSS from 'rss'
export const Route = createFileRoute('/rss.xml')({
server: {
handlers: {
GET: async () => {
const siteUrl = env.PUBLIC_BASE_URL
const feed = new RSS({
title: '<Your Title Here>',
description:
'<Your description Here>',
feed_url: `${siteUrl}/rss.xml`,
site_url: siteUrl,
language: 'en',
pubDate: new Date(),
copyright: `All rights unreserved ${new Date().getFullYear()}`,
})
allPosts.map((post) => {
feed.item({
title: post.title,
description: post.description,
author: post.authors.join(', '),
url: `${siteUrl}/blog/${post.slug}`,
date: post.published,
custom_elements: [
{ 'content:encoded': { _cdata: post.rendered.markup } },
],
enclosure: post.headerImage
? {
url: post.headerImage,
type: 'image/jpeg',
}
: undefined,
})
})
return new Response(feed.xml({ indent: true }), {
status: 200,
headers: {
'Content-Type': 'text/xml',
},
})
},
},
},
})
Configuration
- In your headers you can control how long your want to cache this for or not at all
- There is more rss options you can configure or less! I like to add the image if it is present as most modern readers will render this in there ui.
Comments
No comments yet. Be the first!