Gatsby に RSS フィードを追加
2020/11/25
はじめに
Gatsby で構築したブログに RSS フィードを追加する場合、公式ドキュメントの通りにやればほぼ問題ないんですが、ちょっとだけ日本特有の追加対応をしたので、そのメモです。
対応内容
前提
- pubDate には yyyy-mm-dd 形式の
edge.node.frontmatter.date
を利用。 - custom_elements は使わず、description には
edge.node.excerpt
を利用。
日本特有の問題
pubDate 時差問題
何も考えずに公式ドキュメントの通りに edge.node.frontmatter.date
をそのまま使うと、GMT として解釈されてしまいます。
例えば、date: "2020-11-25"
の場合、下記の通りに出力されます。
<pubDate>Wed, 25 Nov 2020 00:00:00 GMT</pubDate>
例の如く、直接使っている gatsby-plugin-feed は Gatsby 用アダプタ的な位置付けで、実処理は他のライブラリに移譲しており、そちらのマニュアルを見ると、itemOptions
の date
は Date object or date string
と説明があります。date string
のフォーマットって何だろう・・・と、あまりピンと来なかったので、実コードを読んでみると、pubDate は new Date(item.date).toGMTString()
で生成されているようでした。
上記を踏まえ、対応選択肢はいくつかありますが、正しい Date オブジェクトを渡す方針で進めます。具体的には Moment.js で正しく変換してあげます。
- date: edge.node.frontmatter.date,
+ date: moment(edge.node.frontmatter.date).toDate(),
これで下記の通り、意図した出力になりました。
<pubDate>Tue, 24 Nov 2020 15:00:00 GMT</pubDate>
excerpt 問題
gatsby-transformer-remark のドキュメントに記載されている通り、文字数ベースで excerpt を利用する際、日本語使うなら truncate
オプションを使いましょう。そうでないと変な所でバッサリ切られてしまいます。
実対応
ライブラリ追加
yarn add gatsby-plugin-feed moment
gatsby-config.js 差分
+const moment = require('moment');
+
module.exports = {
siteMetadata: {
title: 'リアキテク・ラボ Tech Blog',
@@ -47,5 +50,42 @@ module.exports = {
},
'gatsby-plugin-react-helmet',
'gatsby-plugin-sitemap',
+ {
+ resolve: 'gatsby-plugin-feed',
+ options: {
+ feeds: [
+ {
+ serialize: (
+ { query: { site, allMarkdownRemark } },
+ ) => allMarkdownRemark.edges.map((edge) => ({
+ ...edge.node.frontmatter,
+ description: edge.node.excerpt,
+ date: moment(edge.node.frontmatter.date).toDate(),
+ url: site.siteMetadata.siteUrl + edge.node.fields.slug,
+ guid: site.siteMetadata.siteUrl + edge.node.fields.slug,
+ })),
+ query: `
+ {
+ allMarkdownRemark(
+ sort: { order: DESC, fields: [frontmatter___date] },
+ ) {
+ edges {
+ node {
+ excerpt(truncate: true, pruneLength: 280)
+ html
+ fields { slug }
+ frontmatter {
+ title
+ date
+ }
+ }
+ }
+ }
+ }`,
+ output: '/rss.xml',
+ },
+ ],
+ },
+ },
],
};
おわりに
時差問題。日本語処理問題。ありがちです。
あと、本題とは全然関係ないんですが、Date オブジェクトをコンストラクタ引数として渡すと同じ Date オブジェクトが複製されるんですね・・・。勉強になりました。