RSS Feeds are a good way to publish your articles and have others consume them at their convenience. People can subscribe to your feed, along with other feeds, and leverage an RSS program that gives them features such as previews, multi-feed aggregation, tagging, favorites, read/unread, new content, etc.
Seems RSS feeds were standardized circa 1999. They started as XML. According to the wikipedia entry, had wide-spread popularity during the 2000s, lost popularity during the 2010s, and have regained interest again 2018+…
After XML, came JSON, and with it an alternative RSS Feed jsonfeed.
It is essentially the same.
I implemented an XML version, and a JSON version on my site.
I went ahead and used non-HTML pages instead of the recommended (at the time) way using getStaticPaths({rss})
.
Because I am doing 2 versions, I encapsulated some things into a helper object rss-feed.js
that I import
on both versions.
//-- /src/rss-feed.js
const feedr = {
domain: "https://www.readonlychild.com",
title: "readonlychild rss feed",
description: "Random post entries.",
items: async () => {
let posts = await import.meta.globEager('./pages/blog/*.md');
let postAry = [];
for (let postkey in posts) {
if (posts[postkey].frontmatter.published && posts[postkey].frontmatter.title) {
postAry.push(posts[postkey]);
}
}
postAry.sort((a, b) => {
if (a.frontmatter.published < b.frontmatter.published) return 1;
return -1;
});
return postAry;
}
};
export default feedr;
Holds domain, title, description, and a function items
that uses import.meta.globEager
to pick up my md
files.
//-- /src/pages/rss-feed.xml.js
import feedr from './../rss-feed.js';
export async function get() {
let xml = [];
const domain = feedr.domain;
xml.push('<?xml version="1.0" encoding="utf-8"?>');
xml.push('<rss version="2.0">');
xml.push('<channel>');
xml.push(`<title>${feedr.title}</title>`);
xml.push(`<link>${domain}/blog/</link>`);
xml.push(`<description>${feedr.description}</description>`);
xml.push(`<lastBuildDate>${new Date().toString()}</lastBuildDate>`);
let posts = await feedr.items();
posts.forEach(async (post) => {
let categories = '';
post.frontmatter.tags.forEach((tag) => {
categories += `<category><![CDATA[${tag}]]></category>`;
});
xml.push(`<item>
<title><![CDATA[${post.frontmatter.title}]]></title>
<link>${domain}${post.url}</link>
<guid>${domain}${post.url}</guid>
<description>
<![CDATA[
<img src="${post.frontmatter.og.basic.image}" /><br/><br/>
${post.frontmatter.summary}
<br/><br/>[ <a href="${domain}${post.url}">Read full post</a> ]
]]>
</description>
<pubDate>${post.frontmatter.published}</pubDate>
${categories}
</item>`);
});
xml.push('</channel>');
xml.push('</rss>');
return {
body: xml.join('')
};
};
import feedr from './../rss-feed.js';
export async function get() {
let feed = {};
const domain = feedr.domain;
feed.version = 'https://jsonfeed.org/version/1.1';
feed.title = feedr.title;
feed.home_page_url = `${domain}/blog/`;
feed.feed_url = `${domain}/rss-feed.json`;
feed.description = feedr.description;
//feed.icon = ''; <!-- other props -->
//feed.favicon = '';
//feed.authors = [ { name url avatar } ];
//feed.language = 'en' | 'en-US'
feed.items = [];
let posts = await feedr.items();
posts.forEach(async (post) => {
feed.items.push({
id: `${domain}${post.url}`,
title: `${post.frontmatter.title}`,
content_text: post.frontmatter.summary,
summary: post.frontmatter.summary,
image: post.frontmatter.og.basic.image,
date_published: post.frontmatter.published,
tags: post.frontmatter.tags,
//language: 'en-US',
content_html: `<img src="${post.frontmatter.og.basic.image}"/>
<p>${post.frontmatter.summary}</p>
<p><a href="${domain}${post.url}">Read full post</a></p>`,
url: `${domain}${post.url}`
});
});
return {
body: JSON.stringify(feed,null,2)
};
};
In my case, I chose to provide an image and the summary, along with a link to read the full post.
Most of my posts may include astro components in them and I have not figured out a way to generate the markup with rendered components, to place it in the xml/json.
Seems Ben is working on an rss
integration, which I will be checking out once it drops.