序
- ContentlayerとNext.jsでMarkdown個人ブログを作ったのですが、RSSフィードの実装がまだだったので、組み込んでみました。
サイト
リポジトリ
方針
- 大変ありがたいことに、Contentlayerにはビルド成功時にコールバック関数を呼べる仕組みがあります。
- これを利用してビルド時に
public/rss.xml
が生成されるようにします。
- これを利用してビルド時に
実装
-
rss.ts
ファイルにRSSフィード生成のためのコードを実装します。- 外から
import
しているsortFunction
やDESCRIPTION
等の定数については、ここでは割愛します。
- 外から
rss.ts
import fs from 'fs';
import type { Post } from './.contentlayer/generated';
import { sortFunction } from './src/lib/utils';
import { DESCRIPTION, TITLE, URL_BASE } from './src/lib/const';
const generateRss = (allPosts: Post[]) => {
const path = './public/rss.xml'
const items = allPosts.sort(sortFunction).splice(0, 10).map(post => {
return `<item>
<guid>${URL_BASE}${post.url}</guid>
<title>${post.title}</title>
<description>${post.description}</description>
<link>${URL_BASE}${post.url}</link>
<pubDate>${new Date(post.date).toUTCString()}</pubDate>
</item>`
})
const rss = `<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>${TITLE}</title>
<link>${URL_BASE}</link>
<description>${DESCRIPTION}</description>
<atom:link href="${URL_BASE}/rss.xml" rel="self" type="application/rss+xml" />
${items.join('')}
</channel>
</rss>`
fs.writeFileSync(path, rss)
}
export default generateRss;
- 見ての通りで、Contentlayerで生成したドキュメントから最新の記事10件を取り出し、テンプレートリテラルでひたすら埋め込みます。
contentlayer.config.ts
- Contentlayerの
makeSource
の引数に渡すオブジェクトに、onSuccess
を生やして関数を入れておくと、ドキュメントのビルド成功時に実行してくれます。
import { makeSource } from 'contentlayer/source-files';
import generateRss from "./rss";
/* ... 中略 ... */
export default makeSource({
contentDirPath: 'posts',
documentTypes: [Post],
markdown: {
//@ts-expect-error
remarkPlugins: [remarkDirective, remarkDirectiveRehype, remarkGfm],
rehypePlugins: [
rehypeSlug,
[rehypeAutolinkHeadings, { behavior: 'append' }],
[rehypePrettyCode, { ...prettyCodeOptions }],
],
},
onSuccess: (async (importData) => {
// generate rss feed
const { allPosts } = await importData()
generateRss(allPosts);
})
});
出来るもの
-
./public/rss.xml
にこのような感じでファイルが生えます。-
W3CのFeed Validatorに投げたら
This is a valid RSS feed.
と出たので、大丈夫なはず。
-
W3CのFeed Validatorに投げたら
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>Crumbs on the table</title>
<link>https://kedama-t.netlify.app</link>
<description>技術・思考・読書のメモブログ</description>
<atom:link href="https://kedama-t.netlify.app/rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid>https://kedama-t.netlify.app/posts/tech/01.create_own_blog</guid>
<title>ブログの構築</title>
<description>Next.js + Tailwind CSS + Contentlayer で自分だけのMarkdownブログを作る</description>
<link>https://kedama-t.netlify.app/posts/tech/01.create_own_blog</link>
<pubDate>Fri, 01 Dec 2023 00:00:00 GMT</pubDate>
</item>
<item>
<guid>https://kedama-t.netlify.app/posts/idea/01.remark_memo</guid>
<title>remarkについてのメモ</title>
<description>undefined</description>
<link>https://kedama-t.netlify.app/posts/idea/01.remark_memo</link>
<pubDate>Thu, 30 Nov 2023 00:00:00 GMT</pubDate>
</item>
<item>
<guid>https://kedama-t.netlify.app/posts/booklog/01.booklog</guid>
<title>積本状況 in 202311</title>
<description>あるいはブラックフライデーの戦利品</description>
<link>https://kedama-t.netlify.app/posts/booklog/01.booklog</link>
<pubDate>Tue, 28 Nov 2023 00:00:00 GMT</pubDate>
</item>
<item>
<guid>https://kedama-t.netlify.app/posts/tech/02.app_idea_in_202311</guid>
<title>作りたいもの in 202311</title>
<description>いつか作るかもしれないもの</description>
<link>https://kedama-t.netlify.app/posts/tech/02.app_idea_in_202311</link>
<pubDate>Tue, 28 Nov 2023 00:00:00 GMT</pubDate>
</item>
</channel>
</rss>
終わりに
- Contentlayer、かゆいところに手が届いていいですね。
- RSSってあんまり今時じゃないかもしれないですが、使うと案外便利ですよね。