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

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

【Gatsby】マークダウンファイルの情報を取得してブログ上に表示する

はじめに

前回に引き続き、開発環境にマークダウン形式の記事を保存し、Gatsbyで取得する方法を確認する。

今回は取得したファイルの中身(マークダウン形式)を取得して、解析して最終的にHTMLに変換して表示する方法を確認する。

ここまで参考にしてきたGatsby公式チュートリアルと、gatsby-starter-blogスターターキットとでは、利用するマークダウンの変換方法が異なる。

参考にした方法 ファイル形式 変換プラグイン
公式チュートリアル .mdx gatsby-plugin-mdx
gatsby-starter-blogスターター .md gatsby-transformer-remark

本記事ではmdx形式を利用できるGatsby公式チュートリアルのやり方で実施する。

本記事のゴール

  • 開発環境に保存したマークダウン形式の記事の中身を取得する。
    • 開発環境からデータレイヤーに情報を送信する。
    • データレイヤ内で、ノードの形式を「ファイルノード」から「MDXノード」に変換する。
    • データレイヤーにGraphQLでアクセスし、情報を取得する。
  • 取得したマークダウン記事をブログに表示する。

赤枠が本記事の実施範囲である。青枠が前回の実施範囲となる。

前回の記事

tomiko0404.hatenablog.com

前提

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

参考にしたサイト

www.gatsbyjs.com

MDXファイルとは

基本的にマークダウン形式のファイルだが、JSXの形式も書いて良いよ!という形式。

通常のマークダウンでは、マークダウンまたはHTMLしか書けないが、

console.log(""); // インデントするとJSとして動かないらしいので注意

<MyComponent title="あああ"></MyComponent>

のようなものを書くことができる。

詳細は以下サイトを参照。

What is MDX? | MDX

ファイルノード・MDXノードとは

データレイヤーに取り込まれたデータの1つ1つは「ノード」と呼ばれる.。

  • ノードの種類は、ソースプラグインごとに異なる。
  • ノードの種類によって持つフィールドは異なる。

sorce-filesystemプラグインを利用した場合、「ファイルノード」が作成される。

ファイルノードには、例えばファイル名を表すnameや、更新日時を表すmodifiedTime等のフィールドがあり、以下のようにクエリで取得することができる。ただし、マークダウンで書かれたファイルの中身を上手く取得できるようなフィールドは無い。

query {
  allFile {
    nodes {
      id
      name
    }
  }
}

そこで、「MDXノード」に変換する必要がある。

MDXノードは、body(本文)や、frontmatterに記載した内容、slug(ファイル名)等を取得することができる。

query MyQuery {
  allMdx {
    nodes {
      frontmatter {
        title
      }
      slug
      body
    }
  }
}

ファイルノードをMDXノードに変換する

MDXファイルの中身をつくる

MDXファイルに記事の内容を書く。 冒頭にはfrontmatterを記載することができる。

frontmatterの下にはマークダウン+JSX(今回は単なるマークダウン)で記事を記載する。

frontmatterとは

frontmatterとは、英単語で言うと「本の奥付」。

まず Front Matter とはなんぞや、というと、元々は Jekyll という静的サイトジェネレータが広めたらしい、文書のメタデータYAML で書く手法。 Markdown ファイルに限らず、そのファイルの冒頭で、以下のようにハイフン3つで囲んだ行の中が YAML 形式になっていて、その部分をメタデータ的に活用できるというモノ。
Remark プラグインを使って Markdown から Front Matter を抽出する - Neo's World

ということ。

マークダウンファイルの冒頭に以下のように記載する。

/content/blog/mdx-content.mdx

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

記事を取得した際、node.frontmatter.titlenode.frontmatter.dateとして値を取得できる。

また、上記のdateのように"xxxx-xx-xx"という形式のデータを入れておくと、GraphiQLで要求電文を作成するとき、formatStringという様々な日付形式に変換できるフィルターをサジェストしてくれるので便利。

プラグインの利用設定

インストール

gatsby-plugin-mdxをインストールする。

gatsby-plugin-mdx | Gatsby

$ npm install gatsby-plugin-mdx @mdx-js/mdx@v1 @mdx-js/react@v1

コンフィグファイル設定

gatsby-config.jsplugin配列の中に、以下のように記載を追加する。

plugins: [
        `gatsby-plugin-image`,
        {
            resolve: `gatsby-source-filesystem`,
            options: {
                path: `${__dirname}/content/blog`,
                name: `blog`,
            },
        },
        {
            resolve: `gatsby-source-filesystem`,
            options: {
                name: `images`,
                path: `${__dirname}/src/images`,
            },
        },
        // 省略
        `gatsby-plugin-mdx`,  // 追加
    ],

MDXノードの値を取得する

blog-tutorialコンポーネントで、MDXノードの値を取得する。

取得した値は、props.dataに格納されるため、コンポーネント上で表示する。

src/pages/blog-tutorial.js

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

const BlogTutorial = (props) => {
    const { data } = props;
    console.log(data);
    return (
        <MyLayout pageTitle="ブログ一覧">
            {data.allMdx.nodes.map((node) => (
                <article>
                    <h2>{node.frontmatter.title}</h2>
                    <p>Posted: {node.frontmatter.date}</p>
                    <MDXRenderer>
                        {node.body}
                    </MDXRenderer>
                </article>
            ))}
        </MyLayout>
    );
};

export const query = graphql`
    query {
        allMdx(sort: { fields: frontmatter___date }) {
            nodes {
                frontmatter {
                    title
                    date(formatString: "YYYY年MM月DD日")
                }
                id
                body
                parent {
                    ... on File {
                        modifiedTime
                    }
                }
            }
        }
    }
`;

各フィールドの説明

allMdxで取得できるフィールドを説明する。

フィールド 説明
frontmatter.title MDXファイルのfrontmatterにtitleタグをつけて記載した内容を取得。
frontmatter.date MDXファイルのfrontmatterにtitleタグをつけて記載した内容を取得。(formatString: "")オプションをつけると日付形式を指定できる。
リファレンス:Moment.js | Docs
id 各ノードを一意に識別するための文字列ID。<li>要素を使うときのキーにも利用できる。
body ファイルの中身からfrontmatterを除いたもの。
parent MDXに変換する前のノードを示す。ここでは、「対応するファイルノード」を示す。

MDXを読み込む

ファイルから取得したbodyはそのままでは読み込めない。

<MDXRenderer>コンポーネントとセットで利用する必要がある。

上記ソースコードの通り、

import { MDXRenderer } from "gatsby-plugin-mdx";

でインポートして、

<MDXRenderer>
    {node.body}
</MDXRenderer>

で囲む。

結果表示

localhost:8000/blog-tutorialページに、MDX記事の内容を表示できた。

記事の内容を表示できた
記事の内容を表示できた

【参考】他に必要なプラグイン

公式チュートリアルで紹介されていた、記事作成に必要なプラグインは以下。

他にも gatsby-remark-prismjs-add-title(コードブロックの頭にファイル名を表示する)等も利用できそう。

おわりに

マークダウンで作成した記事のデータを取り込み、GraphQLで取得してコンポーネントで表示することができた。

まだ、記事ごとのページは作成できていないので、次回以降確認する。

関連記事

つづき