Gatsbyで生成したブログにRSSフィードを導入する

2022-07-23

GatsbyのブログにRSSフィードを導入した。

ドキュメントのAdding an RSS Feedに従って実装。

環境

  • Markdownをremarkでパースしている

gatsby-plugin-feed

パッケージのインストール

npm install gatsby-plugin-feed

設定

gatsby-plugin-feedは内部的にdylang/node-rssを利用しており、クエリのフィールド名はこのパッケージのオプションに対応する。

query オプションですべてのRSSに共通したフィールドを指定する。

このクエリは baseQuery として feeds の各要素のクエリ実行結果に統合される

例えば gatsby-config.js に設定したメタ情報である siteUrl をnode-rssのオプションである site_url に指定している。

    {
      resolve: `gatsby-plugin-feed`,
      options: {
        query: `
          {
            site {
              siteMetadata {
                title
                description
                siteUrl
                site_url: siteUrl
              }
            }
          }
        `,

feeds はファイル(locale)ごとに設定する。生成するファイルが1つなら要素は1つとなる。

feeds の各要素では output , query , title , serialize が必須。 serialize には options.query のクエリとfeedごとの options.feeds[n].qeury を統合した実応結果が引数に渡される。

例では siteallMarkdownRemarkserialize 関数の返り値はnode-rssのitemOptionsに対応する。

RSSフィードに画像を設定する

gatsby-config.jssiteMetadata にサムネイルのURLを設定。

module.exports = {
  siteMetadata: {
    title: `蛙のテックブログ`,
    description: `Web系ソフトウェアエンジニアの備忘録`,
    siteUrl: `https://memo.kkenya.com`,
    thumbnailUrl: `https://memo.kkenya.com/favicon.ico`,
    // ...省略
  }
}

gatsby-plugin-feedの options.query に画像URL image_url を指定。

    {
      resolve: `gatsby-plugin-feed`,
      options: {
        query: `
          {
            site {
              siteMetadata {
                title
                description
                siteUrl
                thumbnailUrl
                site_url: siteUrl
                image_url: thumbnailUrl
              }
            }
          }
        `,
        feeds: [

記事ごとの画像設定

seriarize 関数で enclosure を指定する。 全ての記事で共通の画像を設定した。frontmatterで記事ごとにogp画像を設定可能にし、なければデフォルトの画像を取得するなどの対応が考えられる。

module.exports = {
  siteMetadata: {
    // ...
    articleDefaultImageUrl: `${siteUrl}/aritcle_default_image.jpg`,
    articleDefaultImageSize: 1386534,
  },
  plugins: [
    {
      resolve: `gatsby-plugin-feed`,
      options: {
        query: ``,
        feeds: [
          {
            title: "KKenya TechBlog",
            output: "/rss.xml",
            query: ``,
            serialize: ({ query: { site, allMarkdownRemark } }) => {
              return allMarkdownRemark.edges.map(edge => {
                const { excerpt, fields, html, frontmatter } = edge.node
                const { title, date } = frontmatter
                const {
                  siteUrl,
                  articleDefaultImageUrl,
                  articleDefaultImageSize,
                } = site.siteMetadata
                const url = `${siteUrl}${fields.slug}`

                return {
                  title,
                  description: excerpt,
                  date,
                  url,
                  guid: url,
                  custom_elements: [{ "content:encoded": html }],
                  enclosure: {
                    url: articleDefaultImageUrl,
                    size: articleDefaultImageSize,
                  },
                }
              })
            },
          },
        ],
      },
    },
  ],
}

ビルド

devサーバーでは確認できないため、ビルドして確認する。

gatsby build && gatsby serve

動作確認

/rss.xml にアクセス (e.g. http://localhost:9000/rss.xml )して確かめる。

  • 生成できている
  • 画像が設定されている
  • HTMLの head にフィードのリンクが設定されている
<link rel="alternate" type="application/rss+xml" title="KKenya TechBlog" href="/rss.xml">

デプロイ後は実際にRSSリーダーでフィードの購読、サムネイル画像が表示されていること。

Feed Validation Service

W3CのFeed Validation Serviceで仕様に準拠しているか検証できる。 URLを入力しCheckを実行すると、RSSフィードを取得され有効な形式であること・より適切な形式があるか確認できる。 生成したXMLを Validate by Direct Input に入力し、ローカルのXMLを検証することも可能。

rss_feed_validator_result

メモ

gatsby-plugin-feedでfor...ofを利用し配列の要素をimmutableに操作していた

gatsby/packages/gatsby-plugin-feed/src/gatsby-node.jsのコードリーディングで詰まったのでメモ。

arr = [
  { title: 'a', query: 'aaa' },
  { title: 'b', query: 'bbb' },
  { title: 'c', query: 'ccc' }
]
// スプレッド構文で展開することによって arr の要素をシャローコピーする
// スプレッド構文がない場合後続のfeed.resultの代入でarrの各要素が破壊的に変更される
for (const { ...feed } of arr) {
  feed.resut = `result: ${feed.title} run ${feed.query}`
  console.log(feed)
}
// { title: 'a', query: 'aaa', resut: 'result: a run aaa' }
// { title: 'b', query: 'bbb', resut: 'result: b run bbb' }
// { title: 'c', query: 'ccc', resut: 'result: c run ccc' }

参考


Web系ソフトウェアエンジニアの備忘録

Contact: 3982ne@gmail.com