ブログ記事にタグが付くようになりました

このブログ環境にもタグをつけられるようになりました。

せっかくあたらしいブログ環境も用意したことですし、何か記事を書いてみようということで、このへんの実装について書いてみます。

Gatsbyのチュートリアル の実装を完了した状態で以下のような作業をします。

1. 記事マークダウンファイルにtags属性を追加する

記事にタグを設定します。タグの付与はこの作業でおしまいです。

  ---
  title: "ブログにタグが付くようになりました"
  date: "2022-02-25"
+ tags: ['プログラミング']
  ---

2. タグで絞り込めるようにする

タグをつけただけでは閲覧性は向上せず、ありがたみがありません。タグに属するページ一覧を表示できるようにします。

Gatsby は、ディレクトリ構造によるルーティングの決定のほかに、プログラマブルにページを追加できる機能がいくつかあります。 今回は、createPages API を使ってタグページを作ります。

まずは、ページのもとになるテンプレートページを作ります。ページ生成時に実行する query とページ(Reactコンポーネント) Tags をExportします。 タグのタイトルや、タグに属するページの一覧が表示できるように実装します。

// src/templates/tag.js

import * as React from 'react'
import { graphql, Link } from 'gatsby'

export default function Tags({pageContext, data}) {
  return (
    <>
      <header>
        <h1>{ pageContext.tagName }</h1>
      </header>
      <article>
        <ul>
          {data.allMdx.nodes.map(item => (
            <li key={item.frontmatter.url}>
              <Link to={item.frontmatter.url}>
                { item.frontmatter.title }
              </Link>
              <time dateTime={item.frontmatter.date}>
                { item.frontmatter.date }
              </time>
            </li>
          ))}
        </ul>
      </article>
    </>
  )
}

// $tagName のタグを date の降順で取得するクエリ
// ページ生成時に実行される
export const query = graphql`
  query TagItems($tagName: String) {
    allMdx(filter: {frontmatter: {tags: {eq: $tagName}}}, sort: {fields: frontmatter___date, order: DESC}) {
      nodes {
        frontmatter {
          title
          date
          tags
        }
        slug
      }
    }
  }`

ページ生成時に query が実行されることで、Tags コンポーネントの引数の data キーにクエリの実行結果が格納されます。 また、pageContext オブジェクトは、このコンポーネントに基づきページを生成する際にセットされるオブジェクトです。以下のような形式のオブジェクトが渡されることを期待しています。

{
  pageContext: {
    tagName: '~~~'
  }
}

また、pageContext内のキー名は query内の変数にも対応しています。($tagNamepageContext.tagName がセットされる)

続いて、以下のように gatsby-node.js に追記します。(ビルド時に gatsby-node.js が実行されます)。

// gatsby-node.js

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions
  
  // 全てのマークダウンファイルからタグのリストを取得するクエリ
  const tags = await graphql(`
    query {
      allMdx {
        distinct(field: frontmatter___tags)
      }
    }
  `)

  // 取得したタグのリストからページを生み出す
  // createPage 関数は path に指定したURLに component をページとして生成する
  tags.data.allMdx.distinct.forEach(tagName => {
    createPage({
      path: `/weblog/tags/${tagName}`,
      component: path.resolve(`./src/templates/tags.js`),
      context: {
        tagName
      },
    })
  })
}

概ね以下のことを行っています。

  • すべてのマークダウンファイルから先ほど付与したタグを抽出し、タグリスト tags を作ります
  • tags の分だけページを生成します

先ほどのテンプレートページに登場した pageContext は、createPage 関数の context キーに渡すオブジェクトが渡されます。

これで、こんなかんじ のように、タグページを生成できました。タグによる分類ができるようになったことで、閲覧性が向上しました。

Gatsbyでマークダウンファイルなどのアセットを利用してルーティングを定義したり、ページを生み出したりする方法が分かったので、いろいろと応用できそうです。

ではではー