エンジニアを目指す日常ブログ

日々勉強したことのメモ。独学ですので間違っていたらコメント等で教えてください。

【Gatsby】マークダウンファイルから記事ページを生成する

はじめに

前回、マークダウンのファイル情報をデータレイヤに取り込み、ブログ上に表示することができた。

今回はブログ記事ページを動的に作成する。

方法としては、

がありそう。

今回はテンプレートコンポーネントを作成する方法を利用する。

本記事のゴール

  • ブログ記事ページのテンプレートを作成する。
  • 開発環境に保存したマークダウン形式の記事の中身と、テンプレートから、記事ごとのページを自動で生成する。

前回の記事

tomiko0404.hatenablog.com

前提

  • gatsby-starter-blogスターターキットを利用したgatsbyブログを立ち上げ済
  • Vagrantを開発環境として利用
  • Gatsby Cloudで公開済(今回は利用しないので、なくても可)
  • gatsby-source-filesystemの設定が完了し、/content/blogフォルダ内のファイルがデータレイヤーに読み込まれる状態になっている
  • gatsby-plugin-mdxの設定が完了し、ファイルをMDXファイルとして利用できる状態になっている

参考にしたサイト

www.gatsbyjs.com

テンプレートとマークダウンから動的にページを作成する流れ

  1. マークダウンファイルを作成する
  2. テンプレートコンポーネントを作成する
  3. テンプレートコンポーネント内で、特定の(URLに対応する)マークダウンから情報を読み込むソースコードを記述する
  4. ビルドする

マークダウンファイルを作成する

前回の記事を参考に、MDXファイルを作成する。

content/blog/mdx-content.mdx

---
title: "mdxで記事を書いてみる"
date: "2022-02-26"
---

## はじめに
記事の内容

テンプレートコンポーネントを作成する

テンプレートコンポーネントを作成する。

作成する場所

pages配下の、URLに対応する場所に作成する。

例えば、ブログ記事ページのURLを~~~~.com/blog/記事名にしたい場合、テンプレートコンポーネントsrc/pages/blog/配下に作成する。

コンポーネントのファイル名

{mdx.slug.js}とする。

構文としては

{{データレイヤのノード名}.{URLに利用したいフィールド名}.js}

となる。

今回は、mdxノードを利用し、URLにはslugフィールドを利用するので{mdx.slug.js}となる。

別のフィールドを使いたい場合

{URLに利用したいフィールド名}が深い場所にある場合は、__(アンダーバー2つ)でネストして行ける。(例:{mdx.frontmatter__slug}.js

slugフィールドとは

gatsby-plugin-mdxを使ってMDXノードに変換すると、自動的にslugフィールドが生成される。これをURLに利用するとよい。

slugフィールド
slugフィールド

自分でslugを設定する

MDXファイル内に自分でslugフィールドを作成し、ファイル名を

{mdx.frontmatter__slug}.js

とすると、ファイル名とは別に好きなURLにすることができる。

---
title: "mdxで記事を書いてみる2"
slug: "mdx-content-my-slug"
date: "2022-03-07"
---

## はじめに

テンプレートの中身を記載する

テンプレートコンポーネント内で、特定の(URLに対応する)マークダウンから情報を読み込むソースコードを記述する。

クエリの作成

クエリはテンプレートコンポーネントに以下のように記載する。

export const query = graphql`
query ($id: String) {
    allMdx(filter: {id: {eq: $id}}) {
      nodes {
        body
        slug
        frontmatter {
          date(formatString: "MMMM D, YYYY")
          title
        }
      }
    }
  }
`
query ($id: String)

は、id変数を引数として利用するという宣言。

allMdx(filter: {id: {eq: $id}}) {

は、idフィールドが$idと等しいもののみ抽出するという指定。

参考:変数を引数としてクエリに設定する方法のメモ tomiko0404.hatenablog.com

変数に入れる値の取得方法

クエリえMDXノードの情報を取得する際に「どのページか」を判定する必要がある。

Gatsbyでは、ページテンプレートコンポーネントを使って作られたページにおいて、props.pageContextの中に、MDXノードを一意に特定するidの値が初めから入っているためこれを利用する。

props.pageContextにはidと、URLに利用したいフィールド名(ここではslug)が自動で渡される。

以下ページによると、ページ生成時にprops.pageContextとして渡された値はGraphQLの引数としてそのまま利用できる。

// Add optional context data to be inserted
// as props into the page component.
//
// The context data can also be used as
// arguments to the page GraphQL query.
//
// The page "path" is always available as a GraphQL
// argument.
Gatsby Node APIs | Gatsby

そのため、前節のクエリを記載するだけで、ページに特有のidをフィルタ条件として利用してくれる。

pageContextについては勉強不足のため割愛する。

テンプレートコンポーネントソースコード

全体としてソースコードは以下のようになる。

src/pages/blog/{mdx.slug}.js

import { graphql } from 'gatsby';
import { MDXRenderer } from 'gatsby-plugin-mdx';
import * as React from 'react';
import MyLayout from '../../components/myLayout';


const BlogPost = (props) => {
    console.log(props);
    const {data} = props;
    return (
        <MyLayout pageTitle="Super Cool Blog Posts">
            <MDXRenderer>
                {data.allMdx.nodes[0].body}
            </MDXRenderer>
        </MyLayout>
    )
}


export const query = graphql`
query ($id: String) {
    allMdx(filter: {id: {eq: $id}}) {
      nodes {
        body
        slug
        id
        frontmatter {
          date(formatString: "MMMM D, YYYY")
          title
        }
      }
    }
  }
`

export default BlogPost

今回は勉強の流れでallMdxフィールドを利用し、idを指定することで要素数1の配列を取得・表示している。

1件のMDXノード情報だけ取れればよいので、mdxフィールドを利用するのがよさそう。

おわりに

テンプレートコンポーネントを作成して、ブログ記事ページを自動で生成することができた。