Gridsomeでイチからブログを作る - RSSを配信する

Gridsomeでブログを作るシリーズ。今回はビルド時にRSSを配信する機能を追加します。RSSを使う理由と、良い感じに配信する方法も合わせてみていきます。

RSS is何?

RSS(バージョンによってRich Site Summary, RDF Site Summary, Really Simple Syndication)は、ニュースやブログなど各種のウェブサイトの更新情報を配信するための文書フォーマットの総称である。
RSS - Wikipedia

要はブログの更新情報を配信する仕組みです。フィード、とも呼ばれます。特筆すべきは、もともとはRSSリーダーのような専用リーダーで購読(サブスクリプション)されるのを想定して配信されていました。

なぜいまだにRSSを使うのか

最近ではRSSリーダーで読む行為自体は下火になってきた印象です。RSSリーダーのような専用アプリケーション(またはWebアプリ)を使わず、TwitterやSlackでブログの更新情報を取得してる人も少なくない印象をうけます。

しかしながら、そのSlackやTwitterに流すもとを辿ればやはりRSSであることが多く、RSSで配信することはいまだに有効です。他にも、IFTTなどと連携し、ブログ更新→RSS配信→IFTT→自分のTwitterで更新を投稿、のような自動化もできます。

GridsomeでRSSを配信する

基本的にはプラグインを入れて、設定をするだけなので簡単です。GridsomeのRSS配信プラグインはいくつかありますが、今回はgridsome-plugin-feed - Gridsomeを使います。

$ yarn add gridsome-plugin-feed

オフィシャルの説明にあるように、基本的な使い方はgridsome.config.jsに設定を加えるだけです。基本的にはデフォルト設定どおりで問題ありません。ちなみにこのgridsome-plugin-feedは内部的にfeed - npmを使っているようです。

それでは前回までの設定を踏襲して見てみましょう

module.exports = {
  plugins: [
    {
      use: 'gridsome-plugin-feed',
      options: {
        // 必須: 記事用のGraphQLスキーマタイプ, VueRemarkのoptions.typeNameと同一です
        contentTypes: ['Post'],
        // オプショナル: `Feed()` コンストラクタ用設定
        // 設定可能なプロパティは https://www.npmjs.com/package/feed#example を参照
        feedOptions: {
          title: '俺のつくったすごいブログのフィード',
          description: '最高のブログフィード'
        },
        // === 以下は全てデフォルト値があります ===
        // オプショナル: フィードの配信URLと配信形式
        rss: {
          enabled: true,
          output: '/feed.xml'
        },
        atom: {
          enabled: false,
          output: '/feed.atom'
        },
        json: {
          enabled: false,
          output: '/feed.json'
        },
        // オプショナル: フィードの配信記事数
        maxItems: 25,
        // オプショナル: 相対パスのリンクを絶対パスに変更する対象
        // 無効化するには `null` をセットします。
        htmlFields: ['description', 'content'],
        // オプショナル: siteURLの末尾スラッシュで終わるようにするか否か
        enforceTrailingSlashes: false,
        // オプショナル: フィルタ。trueのものがフィード対象となります。
        // 例: 過去記事のみにする場合: `filterNodes: (node) => node.date <= new Date()`
        filterNodes: (node) => true,
        // オプショナル: `Feed.addItem()`を利用して内容の変更
        // 設定可能なプロパティは https://www.npmjs.com/package/feed#example を参照
        // NOTE: `date` field は Javascript の `Date` object であること
        nodeToFeedItem: (node) => ({
          title: node.title,
          date: node.date || node.fields.date,
          content: node.content
        })
      }
    }
  ]
}

このようになっています。
デフォルト値が一般的なものとしてカバーしているので、オプショナルな項目にあまり手をいれなくても問題ないことが多いと思います。

なお、このプラグインはdevelop時にはRSSの生成は行なわず、build時にのみ生成するようです。つまり、実際に生成されるRSSを見たい場合は一度buildしてみると良いでしょう。

全文を配信したくない場合

例えばフィードに全文を含めてしまうと、RSSリーダー上で全文が確認できてしまい、自サイトへの流入が減る懸念もあることでしょう。デフォルトの設定だとcontent全てを配信するため、全文を配信してしまいます。
ちょっとこの設定を変えてみましょう。

案1. descriptionを配信する

frontmatter側で記事のdescriptionを別途設定している場合、contentの変わりにdescriptionを配信するようにできますね。具体的には、記事側のmarkdownファイルで

---
title: 最初の記事
description: 最初の記事なんです
cover_image: ogp.jpg
---
これは私の最初の記事です

のようにfrontmatterでdescriptionを設定します。

そして、先程のプラグインの設定で

module.exports = {
  plugins: [
    {
      use: 'gridsome-plugin-feed',
      options: {
        // 中略...
        nodeToFeedItem: (node) => ({
          title: node.title,
          date: node.date || node.fields.date,
          content: node.description // ここをdescriptionにする
        })
      }
    }
  ]
}

こうすることでRSSのcontentに入るのはdescriptionになりますね。

案2. 本文の文字数を制限する

gridsome.config.jsはJavaScriptのファイルなのでもちろん内部でJavaScriptを使うことができます。指定した文字数以下ならそのまま、以上なら文字数でカットして三点リーダーを末尾に付与する関数を作って使ってみましょう。

// 文字列を操作する関数を定義
function toFeed(content) {
  const MAX_LENGTH = 140
  if (content.length <= MAX_LENGTH) {
    return content
  }
  return `${content.substr(0, MAX_LENGTH)}`
}

module.exports = {
  plugins: [
    {
      use: 'gridsome-plugin-feed',
      options: {
        // 中略...
        nodeToFeedItem: (node) => ({
          title: node.title,
          date: node.date || node.fields.date,
          content: toFeed(node.content) // 定義した関数を使う
        })
      }
    }
  ]
}

余談

なお、個人的にはRSSは全文配信したい派なのでこれは使っていません。そもそも情報を使えるよりも自サイトへの訪問を重視するケースは広告を見せたいか、来た人がそのままブログに留まって回遊(他の記事を見る行動)をして欲しいケースだと思っています。

RSSリーダーを使うようなリテラシを持つ人はそもそも広告へアクセスしないですし、そもそもブログのデザインよりRSSリーダーのようなデザインや情報を絞った状態で読みたい人と仮定しています。回遊も同じく、他の記事も気になるなら全文配信しようとも来ると仮定しています。

その場合において、全文を配信しないとわざわざサイトに訪れる必要がありBad UXから印象がわるくなると思っているため、RSSには全文を配信したい派です。
(個人の見解です)

RSSにHTMLを含める

RSSリーダーのほとんどは文中のHTMLタグを解釈してくれます。特に強調やコードブロックなどはRSSリーダー上で見ても指定して解釈されているほうが都合がいいことが多いです。

VueRemarkを使って記事を書いている場合、node.contentにはmarkdownの本文がそのまま入っています。これをHTML化してRSSとして配信したいと思います。

まず、別途Remarkを入れます

$ yarn add remark

その他にもremark-htmlが必要ですが、これはVueRemarkを入れていれば依存ライブラリなので入っているはずです。あとは上で挙げた文字列カットと同じような方法でやればOKです。具体的に見てみましょう

// 必要なライブラリを読み込み
const remark = require(`remark`)
const html = require(`remark-html`)

// markdownをHTML化する関数を定義
function markdownToHtml(content) {
  let result
  remark()
    .use(html)
    .process(content, (err, file) => {
      if (err) throw err
      result = file.contents
    })
  return result
}

module.exports = {
  plugins: [
    {
      use: 'gridsome-plugin-feed',
      options: {
        // 中略...
        nodeToFeedItem: (node) => ({
          title: node.title,
          date: node.date || node.fields.date,
          content: markdownToHtml(node.content) // 定義した関数を使う
        })
      }
    }
  ]
}

これでmarkdownで書かれたcontentがHTML化して配信されます。
特に画像などをRSSでも載せたい場合にはこの方法が良いですね!

まとめ

今回はRSSを生成、配信する方法を応用を交えて紹介してみました。どうしてもpluginで対応している限界もありますが、更新通知し、RSSリーダーで読ませるには十分かと思います。ブログサービスなどではここまで手を入れられないことが多いので、自分で楽にカスタムできるのはとてもいいですね。

pluginに渡す値を加工する方法は別のpluginの利用時にも応用できます。だんだんとブログに必要な機能が充実してきましたね。次回もまたこの調子で必要な機能を追加していきましょう。

僕のReleaseNote[0.38.6] & 僕のRoadMap[0.38.7]Gridsomeでイチからブログを作る - metaタグやOGPを最適化する