DEV Community

Burak Yigit Kaya
Burak Yigit Kaya

Posted on • Originally published at byk.im on

Having a Good Ol' RSS Feed in Astro

After reviving this blog with Astro, I realized that I didn’t have an RSS feed even though the theme I’m using already has support for that. So I got to work to enable it. For some reason, I just did not have the rss.xml file generated. After much trial and error, I finally figured out that the method name in theendpoint definition should be ALL_CAPS as in GETinstead of get. I’m guessing this was because of a major Astro version upgrade since the demo page for Pacamara has a working RSS feed. Fixed that and problem solved, right? RIGHT?

Sort of.

Yes, I got a feed but I noticed 3 major problems:

  1. The feed did not have the full content of the posts
  2. The feed did not limit the number of entries
  3. The feed did not sort the posts in any way

Although unsorted and uncapped posts was not a big deal as I only had 3 posts at the time, it looked like an easy fix so I started with that:

const MAX_ITEMS = 10;

const posts = (await getCollection("posts"))
  .sort(descDateSort)
  .slice(0, MAX_ITEMS);
Enter fullscreen mode Exit fullscreen mode

Quite straightforward: get all the posts, sort by date in descending order, and slice the first 10. Don’t know why this is not the default or a least is offered through a built-in helper, but let’s move onto the bigger issue.

Getting the full content of the posts in RSS was much trickier as the RSS endpoint was defined as an “endpoint” and was not able to render Astro components. Even the recipe for RSS on Astro docs says this is only possible for Markdown only and it uses a custom Markdown renderer 🤯. But I was determined, and was a devotee of “the search church” so off I went to find a solution.

Although there was this very creative solution, I bumped into a more straightforward one first: https://blog.damato.design/posts/astro-rss-mdx/. This solution uses the new and experimental Astro Containers to be able to render an Astro component in isolation inside the endpoint. I followed the instructions and voilà! I had a working RSS feed with full content indeed. Committed, pushed, and got yelled at by GitHub Actions with the following cryptic error:

cannot test case insensitive FS, CLIENT_ENTRY does not point to an existing file: /home/runner/work/byk.github.io/byk.github.io/dist/client/client.mjs
Enter fullscreen mode Exit fullscreen mode

I ran npm run build on my local terminal immediately, and was able to reproduce the error locally. At least, I was not going to play the “try blind commits to see what the CI says” game.

After searching for this error for about an hour, I realized that something was triggering a client-side render mode in Vite (Astro’s underlying bundler) and I started to remove every single new line of code I added. Indeed, once I disabled the import for both @astrojs/container and @astrojs/mdx the build error disappeared. As to why this was happening, I still had no idea. I kept digging and finally found this random (and very helpful) message on the Astro Containers Stage 3 proposal thread: https://github.com/withastro/roadmap/pull/916#issuecomment-2256059117

// astro.config.mjs -- add the following
{
  vite: {
    ssr: {
      external: ['astro/container', '@astrojs/mdx'],
    },
  },
}
Enter fullscreen mode Exit fullscreen mode

Of course this makes sense! Without the above configuration, Vite tries to put these Astro packages into a client bundle whereas I am strictly operating in a server-side rendering world. Once this is in, the build error went away with MDX rendering still intact. I quickly pushed the code, got my deploy, and had my RSS feed! 🎉

I wanted to test my feed before declaring a complete victory so I loaded it up in Readwise Reader, my RSS reader of choice, and saw that the images were not loading. I quickly realized that I (well, Astro) was using relative paths for the images and that’s simply not how RSS works! I had to make all these image URLs absolute which was supposed be quite straightforward.

For some reason, I couldn’t find that simple answer after much searching. Then I tried to hook into the MDX pipeline to modify the URLs only to be disappointed as the image URLs are generated much later in the process and all I got was a JS identifier for the image source 🤦🏻‍♂️. After more research, I learned all about Astro’s image processing pipeline, found out about its getURL() method, dug into its source code andfinally saw that it uses import.meta.env.BASE_URL as the base!

Easy, I thought: I’ll just set that in the config under vite: {base: '...'}. That didn’t work. Then I tried setting it on the top-level Astro config only to be disappointed again. I also tried some other, sillier things that I don’t want to admit doing here. Finally, like really finally, I found the answer in build.assetsPrefix! Set this to my blog’s main URL, tested in dev mode to make sure it still works, got a full build, checked the rss.xml output and saw that the image URLs were now absolute! 🎉🎉🎉

So, if you ever want the same (Astro blog with full content RSS feed and working images), I hope I can save you some hours with this post.

Oh, by the way, if you want to subscribe to my blog, now you can 😏

Top comments (0)