Zenn
💭

Next.jsでRSSフィードを作る方法

に公開

ライブラリの導入

調査すると、rssと、feedという2つのライブラリを使う方法が見つかりました。

GitHubリポジトリについているスターの数はfeedの方が200ほど多かったのですが、
リポジトリの更新が最近まで行われているのがrssでしたので、
そちらで実装を開始してそのまま使用しました。
(この記事を書いている時点で、rssのリポジトリの最終更新は4ヶ月前ですが、
feedの最終更新は3年前です。)

以下のコマンドで導入できます。

npm install rss
npm install --save-dev @types/rss

実装方法

以下のような感じで、Next.jsのサーバーサイドでRSSを作成して返すようにします。

pages/rss.tsx
import { GetServerSideProps } from "next";
import RSS from "rss";

export const getServerSideProps: GetServerSideProps = async ({ res }) => {
  // フィードの基本情報を設定
  const feed = new RSS({
    title: "サンプルタイトル",
    description: "サンプルディスクリプション",
    feed_url: `https://example.com/rss`,
    site_url: "https://example.com/",
    language: "ja",
    custom_namespaces: {
      media: "http://search.yahoo.com/mrss/",
    },
  });

  // 記事データのサンプル
  const articles = [
    {
      title: "最初の記事",
      description: "最初の記事です",
      url: "https://example.com/articles/first-article",
      date: new Date("2025-01-01"),
      media: {
        thumbnail: "https://example.com/images/thumbnail1.jpg",
      },
      content: "<p>最初の記事</p>",
    },
    {
      title: "次の記事です",
      description: "次の記事です",
      url: "https://example.com/articles/second-article",
      date: new Date("2025-01-02"),
      media: {
        thumbnail: "https://example.com/images/thumbnail2.jpg",
      },
      content: "<p>2番目の記事</p>",
    },
  ];

  // 各記事をRSSフィードに追加
  articles.forEach((article) => {
    feed.item({
      title: article.title,
      description: article.description,
      url: article.url,
      date: article.date,
      custom_elements: [
        {
          "media:thumbnail": {
            _attr: {
              url: article.media.thumbnail,
            },
          },
        },
        // CDATAは以下のように定義できる
        {
          "content:encoded": {
            _cdata: article.content,
          },
        },
      ],
    });
  });

  // レスポンスヘッダーを設定
  res.setHeader("Content-Type", "application/rss+xml; charset=utf-8");

  // RSSフィードを返す
  res.write(feed.xml());
  res.end();

  // ページとしては何も返さない
  return { props: {} };
};

// ページの内容は必要ないため何も表示しない
export default function RSSPage() {
  return null;
}

基本的にはnpmに記載された使い方の通りですが、
CDATAをcustom_elements配下の要素に定義したいことがあり、
そこの使い方がnpmから発見できませんでした。

※コード内の「CDATAは以下のように定義できる」というコメント付近のような書き方で定義できました。

動作確認

ローカルで作成してブラウザに表示させると、以下のようにxmlファイルの内容が表示されます。

ただ、ファイルの内容が表示されても、正しい形式になっているかどうかは不安が残ると思います。
私が行った方法としては、Chromeの拡張機能のRSS Feed ReaderをChromeに入れ、以下のようにきちんと表示されることを確認する方法です。

Discussion

ログインするとコメントできます