feat: implement hack for journal post RSS feed

Astro is currently not able to render the compiled HTML of MDX files to a string.
This makes it impossible to render the content for an RSS feed.

Issue: Container API: render components in isolation
https://github.com/withastro/roadmap/issues/533

Proposal: MDX compiledContent() support
https://github.com/withastro/roadmap/discussions/419

To still be able to have full content for RSS feeds, this dirty hack,
Scott Willsey writes about in his 2-part blog post is needed:

https://scottwillsey.com/rss-pt1/
https://scottwillsey.com/rss-pt2/
This commit is contained in:
Stefan Imhoff
2023-06-13 18:52:13 +02:00
parent aa4b69f29c
commit f3986f9d6c
5 changed files with 74 additions and 1 deletions

View File

@@ -0,0 +1,41 @@
---
import { site } from '../data/site';
import { dateToISO } from '../utils';
import { mapping } from '../mdx-components';
const { allPosts } = Astro.props;
const rssHeaderXml = `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>${site.title}</title>
<description><![CDATA[ ${site.description} ]]></description>
<link>${site.url}</link>`;
const rssFooterXml = ` </channel>
</rss>`;
---
<Fragment set:html={rssHeaderXml} />
{
allPosts.map((post: any) => (
<>
<Fragment
set:html={` <item>
<title>${post.frontmatter.title}</title>
<link>${`${site.url}/${post.frontmatter.slug}/`}</link>
<guid>${`${site.url}/${post.frontmatter.slug}/`}</guid>
<description><![CDATA[${post.frontmatter.description}]]></description>
<pubDate>${dateToISO(post.frontmatter.date)}</pubDate>
<content:encoded><![CDATA[`}
/>
<post.Content components={mapping} />
<Fragment
set:html={`]]></content:encoded>
</item>
`}
/>
</>
))
}
<Fragment set:html={rssFooterXml} />

View File

@@ -0,0 +1,13 @@
---
import path from 'node:path';
import fs from 'node:fs/promises';
const distFolder = './dist';
const filename = 'rss.xml';
const fileUrl = path.join(distFolder, filename);
if (Astro.slots.has('rss-writer')) {
const html = await Astro.slots.render('rss-writer');
await fs.writeFile(fileUrl, html);
}
---

View File

@@ -178,5 +178,6 @@ const webManifest = isProduction && {
@apply overflow-auto rounded-2 p-[1em] font-mono text-code mbe-10 mbs-0;
}
</style>
<slot name="rss-writer" />
</body>
</html>

View File

@@ -1,7 +1,7 @@
---
import { getCollection } from 'astro:content';
import { formatPosts } from '../utils';
import { formatPosts, isProduction, sortMarkdownByDate } from '../utils';
import { site, animation, animationDelay } from '../data/site';
@@ -12,6 +12,13 @@ import PageTitle from '../components/PageTitle.astro';
import Picture from '../components/Picture.astro';
import JournalList from '../components/JournalList.astro';
/* FIXME: Remove hack as soon as this issue is resolved:
* Issue: https://github.com/withastro/roadmap/issues/533
* Proposal: https://github.com/withastro/roadmap/discussions/419
*/
import WriteFile from '../components/WriteFile.astro';
import RssXml from '../components/RssXml.astro';
import { Headline } from '../components';
import { Content as AboutMe } from '../text/homepage/about-me.mdx';
@@ -25,6 +32,9 @@ const formattedLatest = formatPosts(allPosts, { limit: 6 });
const title = 'Stefan Imhoff';
const description = 'Front-End Web Developer from Hamburg, Germany';
const rssPosts = await Astro.glob('../content/journal/**/*.mdx');
rssPosts.sort(sortMarkdownByDate);
---
<GridLayout title={title} description={description} grid="fullsize" class="grid" innerGrid>
@@ -81,3 +91,7 @@ const description = 'Front-End Web Developer from Hamburg, Germany';
<JournalList entries={formattedLatest} />
</article>
</GridLayout>
<WriteFile slot="rss-writer">
<RssXml allPosts={isProduction ? rssPosts : []} slot="rss-writer" />
</WriteFile>

View File

@@ -1,3 +1,7 @@
export const sortByDate = (a: any, b: any) => {
return Date.parse(b.data.date.toISOString()) - Date.parse(a.data.date.toISOString());
};
export const sortMarkdownByDate = (a: any, b: any) => {
return Date.parse(b.frontmatter.date) - Date.parse(a.frontmatter.date);
};