見出し画像

Gatsbyでデータを外部から持ってきて記事を生成する

前回の記事で、GatsbyでのGraphQLの使い方を学ぶことができました。

GraphQLを利用することで、プロジェクト内部のデータや外部サービスのデータに簡単にアクセスできることがわかりました。今回は、GraphQLでデータを取得して、ブログの記事ページを作成していきます。

Gatsbyでブログ記事を作成する考え方

Gatsbyでブログ記事を作成するには、2つやることがあります。1つはブログの記事を書くこと、もう1つはブログ記事のベースとなるテンプレートページを作成することです。

この2つを組み合わせることがブログ記事のページが完成します。

まずはブログ記事のファイルを作成してみましょう。

Gatsbyブログ記事用のMDXファイル作成

まずブログ記事を1箇所で管理するために、blogsフォルダを作成しておきます。srcフォルダには.jsのコードを置いているので、今回はsrcフォルダの外に配置します。

スクリーンショット 2021-11-12 11.16.09

ブログ記事は.mdxという形式で書きます。マークダウンを拡張して、JSXを使えるようになっている形式で、Gatsbyで使いやすい形式です。

スクリーンショット 2021-11-12 11.17.15

blogsフォルダの中に、サンプル記事としてblog1.mdx, blog2.mdx, blog3.mdxというファイルを作成します。この1つ1つのファイルが1つのブログ記事になります。

スクリーンショット 2021-11-12 11.18.51

各ブログ記事を区別できるように以下の内容を書いておきます。

# blogs/blog1.mdx

---
title: "これは最初の記事です"
---

はじめまして!
これは僕の初めてのブログ記事です

こうやって**強調**することもできますよ。
# blogs/blog2.mdx

---
title: "2番目の記事じゃダメですか?"
---

1番目じゃなくて2番目の記事です。
# blogs/blog3.mdx

---
title: "3番目の記事は最高です!"
---

3つも記事を作ったんですか!
最後に作った記事が一番いい記事ですよね?

MDXファイルの書き方

最初の3つのハイフン("-")で区切られている箇所は、frontmatterと言います。ここには、メインのコンテンツ内容ではなく、付随する追加情報を足すことができます。

今回はタイトルを指定してブログの記事のタイトルを設定していますが、他にも日付だったり、カテゴリやタグ情報などを追加することもできます。

項目名を書いて":"で区切って、後ろにその内容を記載します。例としては以下のようになります。

---
title: "これがタイトルです"
datePublished: "2021-11-12"
author: "西松"
---

この下にはコンテンツの内容を記載しています。今回の場合は、ブログ記事の本文ですね。ここでは、markdownとJSXの記法を両方使うことができます。詳細はMDXのコンポーネント一覧を確認してください。

Gatsbyでファイル情報を取得する

gatsby-source-filesystemプラグインを使うことで、プロジェクトにあるファイルをGraphQL Data Layerに入れることができることを覚えているでしょうか。今回のようにブログ記事を作成するためには、このプラグインが必要になります。

まずはプラグインをインストールしましょう。

npm install gatsby-source-filesystem

次に、gatsby-config.jsにプラグインを利用することを伝えます。pluginsの中に、以下を追記します。

{
   resolve: "gatsby-source-filesystem",
   options: {
       name: `blogs`,
       path: `${__dirname}/blogs`,
   }
},

今回、追加でオプションを設定するので、他のプラグインと少し違った形式で追記しています。nameはクエリーで情報源をフィルターする時に使う名前になります。さらにpathでブログ記事がどのフォルダに置いてあるかを指定しています。

ここまでの内容を反映したら、一度ローカルサーバーを再起動して、プラグイン情報が反映されるようにしましょう。うまくいっていれば、GraphiQLでブログ記事の情報が取得できるはずです。

http://localhost:8000/___graphql

左側のExplorerから[allFile]→[nodes]→[name]を選択することで、ブログ記事のファイル名を取得できます。

query MyQuery {
 allFile(filter: {sourceInstanceName: {eq: "blogs"}}) {
   nodes {
     name
   }
 }
}

スクリーンショット 2021-11-12 11.53.57

ここでは、sourceInstanceNameでフィルターをかけています。
これは先程オプションでnameに指定した値になります。これによって、blogsにあるファイル情報だけを取得できています。

GatsbyでMDXデータを読めるようにする

gatsby-source-filesystemでファイル情報を取得することができましたが、このままではまだGatsbyで使うことができません。MDXファイルの内容が、使いやすい形式にできないからです。

そこで、また新しいプラグインを使います。

MDXファイルを活用するためには、transformer pluginというものが必要になります。transformer pluginはファイルのデータを、GraphQL Data Layerで使いやすいように変換してくれるプラグインということになります。

gatsby-source-filesystemで取得したデータは、GraphiQLではallFileという場所にありましたね。gatsby-plugin-mdxプラグインは、allFileにある.mdx形式のデータを、allMDXという場所にデータを変換して格納してくれます。

それでは、gatsby-plugin-mdxプラグインをインストールしましょう。いくつか依存するパッケージもあるので一緒にインストールします。

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

そして、gatsby-config.jsのpluginsにgatsby-plugin-mdxを追記します。

module.exports = {
 ...中略...
 
 plugins: [
   ...中略...
   
   {
     resolve: "gatsby-source-filesystem",
     options: {
       name: `blog`,
       path: `${__dirname}/blogs`,
     }
   },
   "gatsby-plugin-mdx",
 ]
};

これらのプラグインの追加に成功していれば、ExplorerにallMdxとmdxのセクションが表示されるようになります。

画像10

せっかくGraphiQLを表示したので、このあと使うクエリもこのまま作成してしまいましょう。allMdxのデータが使えるようになりましたので、以下のようなクエリに変更します。

query{
 allMdx{
   nodes {
     frontmatter {
       title
     }
     id
     body
   }
 }
}

frontmatterで設定したブログ記事のtitle、ブログ記事ファイル固有のid、ブログ記事内容のbodyを取得します。これでMDXファイルのデータを、使いやすい形で入手することができました。

あとはこのクエリから入手したデータを、Gatsbyウェブサイトで表示するようにするだけです。

Gatsbyでブログ記事の一覧を作成する

個々のブログ記事のページを作成する前に、先程のクエリーを利用して、ブログ記事の一覧ページを作成しましょう。

src/pages内にblogsフォルダを作成し、その中にindex.jsファイルを作成します。

スクリーンショット 2021-11-12 12.11.07

このように配置するとblogs/index.jsは、http://localhost:8000/blogs/にアクセスした時の内容となります。

index.jsには先程のクエリーを利用して、タイトルを一覧にして表示します。

# src/pages/blogs/index.js

import * as React from 'react'
import Layout from '../../components/layout'
import { graphql } from 'gatsby'

const BlogPage = ( { data } ) => {

 return (
   <Layout pageTitle="BlogPage">
     <h1>ブログ一覧</h1>
     <p>ここにタイトルが表示されます</p>
     <ul>
     {
       data.allMdx.nodes.map(node => (
         <li key={node.id}>
           {node.frontmatter.title}
         </li>
       ))
     }
     </ul>
   </Layout>
)
}

export const query = graphql`
 query {
   allMdx{
     nodes {
       frontmatter {
         title
       }
       id
       body
     }
   }
 }
`

export default BlogPage

nodesは複数形になっている通り、複数のnodeが入っています。コードでは、mapを利用することで各nodeにアクセスしています。

また、blogsフォルダを作ったことで、Layoutのインポートpathが少し変わっているので注意してください。

これを実行すると以下のようにタイトルの一覧が表示されます。(少し記事が増えていますが、気にしないでください)

スクリーンショット 2021-11-12 12.29.53

GatsbyでMDXファイルから動的にページを作成する

ブログ記事の一覧が表示されましたが、まだそれぞれの記事のページが作成されていません。

これまではページを追加するために、毎回src/pagesに.jsファイルを追加してきました。でも、ブログ記事のようにページの構成が同じであるならば、同じようなコードを何回も書くのは非効率ですよね。

今回は、MDXファイルを作成して記事を作っているので、MDXファイルを追加するだけで、ブログ記事を作れたら嬉しいですよね。

GraphQLで入手したデータ(data)の処理を行うときに{}で囲んでいたのを覚えているでしょうか?実はファイル名でもこれと同じことができます。

src/pages/blogsフォルダに{mdx.slug}.jsというファイルを作成します。そうするとGatsbyがビルドするときに各MDXファイルのslug情報を入手して、ページを自動的に作ってくれるようになります。

スクリーンショット 2021-11-12 12.38.40

あとはこの{mdx.slug}.jsの内容を作成すれば、ブログ記事のページが作られます。

# src/pages/blogs/[mdx.slug}.js

import * as React from 'react'
import Layout from '../../components/layout'
import { MDXRenderer } from 'gatsby-plugin-mdx'
import { graphql } from 'gatsby'

const BlogPost = ( { data } ) => {

 return (
   <Layout pageTitle={data.mdx.frontmatter.title}>
     <MDXRenderer>
       {data.mdx.body}
     </MDXRenderer>
   </Layout>
 )
}

export const query = graphql`
 query ($id: String) {
   mdx(id: {eq: $id}) {
     frontmatter {
       title
     }
     body
   }
 }
`

export default BlogPost

GraphQLではmdxファイルのIDによって、ブログ記事を区別するようにしています。クエリーに$id: Stringを追加して、$idがマッチするmdxを見つけています。

また、MDXファイルのbodyの内容を正常に表示するためには、MDXRendererを利用する必要があります。GraphiQLでbodyの中身を見るとわかりますが、複雑な形式で書かれています。その複雑な形式を処理して、本文を取り出してくれるのがMDXRendererの役目です。

import { MDXRenderer } from 'gatsby-plugin-mdx'

このファイルを作成した後に、ブラウザでアクセスするとページが表示されるようになりました。

http://localhost:8000/blogs/blog1

スクリーンショット 2021-11-12 12.50.27

実装結果

ブログ一覧ページから個別の記事に飛べるようにする

最後にブログの一覧ページから先程作成した各ブログ記事へのリンクを貼りましょう。リンク先を入手するために、GraphQLでslugを入手するようにしました。そのslugを利用してblogs/index.jsにLinkを追加します。

# src/pages/blogs/index.js

import * as React from 'react'
import Layout from '../../components/layout'
import { Link, graphql } from 'gatsby'

const BlogPage = ( { data } ) => {

 return (
   <Layout pageTitle="BlogPage">
     <h1>ブログ一覧</h1>
     <p>ここにタイトルが表示されます</p>
     <ul>
     {
       data.allMdx.nodes.map(node => (
         <li key={node.id}>
           <Link to={node.slug}>
             {node.frontmatter.title}
           </Link>
         </li>
       ))
     }
     </ul>
   </Layout>
)
}

export const query = graphql`
 query {
   allMdx{
     nodes {
       frontmatter {
         title
       }
       id
       slug
     }
   }
 }
`

export default BlogPage
​

スクリーンショット 2021-11-12 13.08.47

これで記事のタイトルをクリックしたら、記事のページに飛ぶようになりました。

実行結果

まとめ

これでソースコードを変更しなくても、ブログ記事が制作できるようにになりました。MDXファイルを追加すればいつでもブログ記事が追加されます。

また、これと同じようにgatsby-source-XXXプラグインを利用することで、外部サービスと連携することもできます。


ここまで読んでいただけたなら、”スキ”ボタンを押していただけると励みになります!(*´ー`*)ワクワク


この記事が気に入ったらサポートをしてみませんか?