Using built in @astrojs/rss
for generation seems simple but there are a few problems & a lot of missing features.
Problems #
I wanted to generate a feed using an excerpt of the blog post content.
There are two problems with this:
I personally don't have any mdx content in posts so using post.body
with markdown-it
should be ok.
There are a large number of RSS fields completely missing in @astrojs/rss
.
Example missing fields: author, copyright, image, id ...
astro/astro-rss/src/schema.ts
import { z } from 'astro/zod';
export const rssSchema = z.object({
title: z.string(),
pubDate: z.union([z.string(), z.number(), z.date()]).transform((value) => new Date(value)),
description: z.string().optional(),
customData: z.string().optional(),
draft: z.boolean().optional(),
});
withastro/astro/packages/astro-rss/src/schema.ts on Github
The output does not use CDATA sections for HTML.
CDATA sections may occur anywhere character data may occur; they are used to escape blocks of text containing characters which would otherwise be recognized as markup.
W3C Extensible Markup Language (XML) 1.0 (Fifth Edition)
Adding Content #
It is possible to input the content of posts (mdx not supported) using markdown-it
& sanitize-html
.
rss.xml.js
import { getCollection } from 'astro:content'
import { siteConfig } from '~/config'
import createSlug from '~/lib/createSlug'
import slugDate from '~/lib/slugDate'
import sanitizeHtml from 'sanitize-html'
import MarkdownIt from 'markdown-it'
const markdown = MarkdownIt({
html: true,
breaks: true,
linkify: true,
})
content: sanitizeHtml(markdown.render(post.body)),
Adding Excerpt #
I wanted to add an excerpt of the content into the description field of the RSS entries. (most tech blogs I subscribe to do this)
Implementing excerpt can be done in different ways, a lot of implementations just use x
characters.
I decided to do it using words (items seperated by spaces)
title: post.data.title,
description: sanitizeHtml(
markdown.render(post.body).split(' ').slice(0, 50).join(' ')
),
Kind of simple, take post.body
& split
it using spaces as seperator, then use slice
to take the first 50
items, then join
it all back again.
There may be open <p>
tags within the excerpt but any open tags will get closed with sanitize-html
making the code safe.
Fixing Relative Paths #
Using markdown-it
will output relative links & images.
RSS feeds shouldn't have items with relative paths.
To fix this use replace()
on href
& src
objects starting with /
.
description: sanitizeHtml(
markdown
.render(post.body)
.replace('src="/', `src="${siteConfig.url}/`)
.replace('href="/', `href="${siteConfig.url}/`)
.split(' ')
.slice(0, 50)
.join(' ')
),
Notes #
I am looking into generating feeds using an external script (like you would in nextjs)
A few advantages to this over astrojs/rss:
Update February 22, 2023
Webmentions
No Comments Yet