【Gatsby】マークダウンファイルから記事ページを生成する
はじめに
前回、マークダウンのファイル情報をデータレイヤに取り込み、ブログ上に表示することができた。
今回はブログ記事ページを動的に作成する。
方法としては、
- テンプレートコンポーネントを作成する方法(
{mdx.slug.js}
)(Gatsby公式チュートリアルはこちらの方法) createPages
APIを自作する(gatsby-starter-blogスターターキットはこちらの方法)
がありそう。
今回はテンプレートコンポーネントを作成する方法を利用する。
本記事のゴール
- ブログ記事ページのテンプレートを作成する。
- 開発環境に保存したマークダウン形式の記事の中身と、テンプレートから、記事ごとのページを自動で生成する。
前回の記事
前提
- gatsby-starter-blogスターターキットを利用したgatsbyブログを立ち上げ済
- Vagrantを開発環境として利用
- Gatsby Cloudで公開済(今回は利用しないので、なくても可)
gatsby-source-filesystem
の設定が完了し、/content/blog
フォルダ内のファイルがデータレイヤーに読み込まれる状態になっているgatsby-plugin-mdx
の設定が完了し、ファイルをMDXファイルとして利用できる状態になっている
参考にしたサイト
テンプレートとマークダウンから動的にページを作成する流れ
マークダウンファイルを作成する
前回の記事を参考に、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
を設定する
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
フィールドを利用するのがよさそう。
おわりに
テンプレートコンポーネントを作成して、ブログ記事ページを自動で生成することができた。