ホーム > Gatsby > 【Gatsby.js】マークダウンで書いた記事にサムネイルを表示する方法
Gatsby

【Gatsby.js】マークダウンで書いた記事にサムネイルを表示する方法

いつもご利用ありがとうございます。
この記事には広告が掲載されており、その広告費によって運営しています。

⇨ React 記事の目次はこちら

Gatsby.js でマークダウンで記事を書く際に、サムネイルを設定する方法についてまとめました。

はじめに

今回紹介する方法は、2つあります。

画像をおいて絶対パスを指定するだけの簡単な方法と、GraphQL を使って画像を圧縮・軽量化させたものを表示する方法です。

また、画像のプラグインは gatsby-image から、今は gatsby-plugin-image が使われているため、プラグインによって書き方も変わってくるので注意が必要です。

サムネイルを設定する簡単な方法

使用プラグイン

たいていすでに入っていると思いますが、以下のプラグインを入れる必要があります。

npm install gatsby-source-filesystem

画像を置く場所

/static/配下に画像を置きます。

例えば、/static/images/sample.pngという構成で画像を配置します。

gatsby.config.js の記述を確認する

プロジェクトのスタートによっては以下の記述がないかもしれないので、以下の記述があれば OK です。

なければ module.exports のplugins:[]の配列に追加してください。

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

gatsby-node.js に追記

サムネイル用の絶対パスを書く文字列をスキーマの Frontmatter に追加します。

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions
  createTypes(
    //~~~略
    `
    type Frontmatter {
      title: String,
      thumbnail: String, //← 追加
    }
  `
  )
  //~~~略
}

マークダウンにサムネイルのパスを書く

---
title: How to display thumbnails in Gatsby
thumbnail: "/images/sample.png"
---

使うページの graphql で呼び出す

export const query = graphql`
  query PostBySlug($slug: String!) {
    post: markdownRemark(
      fields: { slug: { eq: $slug }}
    ) {
      id
      html
      frontmatter {
        title
        thumbnail // ← frontmatterに追加
      }
    }
  }
`

画像を表示

<img src="{edge.node.frontmatter.thumbnail}" />

以上が簡単な方法です。

GraphQL を使って画像を圧縮・軽量化させる方法

必要なプラグインを入れます

npm install gatsby-plugin-image gatsby-transformer-sharp gatsby-plugin-sharp gatsby-source-filesystem

ファイルを置く場所

今回、絶対パスでの指定ができないため、マークダウンファイルからの相対パスで書きやすい場所に置きます。

├── content
│    ├── blog
     │    └── slug
     │         └── ja.md //記事ファイル
     └── thumbnail
           └── sample.png

記事ファイルからの相対パスは、../../thumbnail/sample.pngになる場所に今回は画像を設置しています。

gatsby-config.js に追記

module.exports のplugins:[]の配列に以下の3つを追加します。

すでに同じ内容が書かれている場合もあるので、注意してください。

    `gatsby-plugin-image`,
    `gatsby-transformer-sharp`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `thumbnail`,
        path: `${__dirname}/content/thumbnail`,
      },
    },

gatsby-node.js の Frontmatter に追記します

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions
  createTypes(
    //~~~略
    `
    type Frontmatter {
      title: String,
      thumbnail: File @fileByRelativePath,
    }
  `
  )
  //~~~略
}

これを書くことで、File タイプの出力がされ、@fileByRelativePath によって相対パスでの指定になります。

ちなみに例えば@fileByRelativePath などを無しにして何とか絶対パスで書けないか、試したりなどしたけど上手くいかなかったので、このやり方で落ち着いてます。

もし自分の見落としだったら教えていただけると嬉しいです。

ちなみに、この書き方はここに書かれています。

Gatsby Node APIs

GraphQL を確認

http://localhost:8000/___graphql

Frontmatter の thumbnail を確認すると色々出力されることが分かります。

表示するページで取得する

さきほど色々出力されるのは確認しましたが、今回使うのは以下の gatsbyImageData というものです。

これを使うことで画像表示プラグインを使って、軽量の画像をいい感じに表示してくれます。

export const pageQuery = graphql`
  {
    allMarkdownRemark() {
      edges {
        node {
          frontmatter {
            title
            thumbnail {
              childImageSharp {
                gatsbyImageData
              }
            }
          }
        }
      }
    }
  }
`

サムネイル画像を表示する

gatsby-plugin-image の GatsbyImage を使用して表示します。

import { GatsbyImage } from "gatsby-plugin-image"

const Posts = ({ data }) => {
  const edges = data.allMarkdownRemark.edges
  return (
    <div>
      {edges.map(edge => (
        <GatsbyImage
          image={
            edge.node.frontmatter.thumbnail?.childImageSharp.gatsbyImageData
          }
          alt=""
          height="140"
        />
      ))}
    </div>
  )
}

export default Posts

export const pageQuery = graphql`
  {
    allMarkdownRemark() {
      edges {
        node {
          frontmatter {
            title
            thumbnail {
              childImageSharp {
                gatsbyImageData
              }
            }
          }
        }
      }
    }
  }
`

Gatsby Image plugin

出力結果を見る

HTML で出力されている結果が以下の通りです。

普通にコーディングしたら大変なので、感謝しかありません。

<picture
  ><source
    type="image/avif"
    srcset="
      /static/638be90904f9f9248d3c69cb2992c562/5e601/react.avif  320w,
      /static/638be90904f9f9248d3c69cb2992c562/14473/react.avif  640w,
      /static/638be90904f9f9248d3c69cb2992c562/1f487/react.avif 1280w
    "
    sizes="(min-width: 1280px) 1280px, 100vw" />
  <source
    type="image/webp"
    srcset="
      /static/638be90904f9f9248d3c69cb2992c562/a0615/react.webp  320w,
      /static/638be90904f9f9248d3c69cb2992c562/6789b/react.webp  640w,
      /static/638be90904f9f9248d3c69cb2992c562/3602f/react.webp 1280w
    "
    sizes="(min-width: 1280px) 1280px, 100vw" />
  <img
    height="905"
    width="1280"
    data-main-image=""
    style="object-fit: cover; opacity: 1;"
    sizes="(min-width: 1280px) 1280px, 100vw"
    decoding="async"
    loading="lazy"
    src="/static/638be90904f9f9248d3c69cb2992c562/eed66/react.png"
    srcset="
      /static/638be90904f9f9248d3c69cb2992c562/aaddb/react.png  320w,
      /static/638be90904f9f9248d3c69cb2992c562/94304/react.png  640w,
      /static/638be90904f9f9248d3c69cb2992c562/eed66/react.png 1280w
    "
    alt=""
/></picture>

ちなみに、className などは props で渡せるので CSS も簡単につけれます。

<GatsbyImage
  className="object-cover h-36 hover:opacity-70 duration-200"
  image={edge.node.frontmatter.socialImage?.childImageSharp.gatsbyImageData}
  alt=""
  height="140"
/>

gatsby-plugin-images の使い方

古い gatsby-image を使っている場合

取得する GraphQL が変わります。

fluid というデータを元に表示してくれるようです。

export const pageQuery = graphql`
  query {
    allMarkdownRemark() {
      nodes {
        frontmatter {
          title
          thumbnail {
            childImageSharp {
              fluid(maxWidth: 1280) {
                ...GatsbyImageSharpFluid
              }
            }
          }
        }
      }
    }
  }
`

表示の書き方

props が fluid になります。

import Image from "gatsby-image"

const BlogIndex = ({ data, location }) => {
  const posts = data.allMarkdownRemark.nodes
  return (
    <div>
      {posts.map(post => {
        const thumbnail = post.frontmatter.thumbnail?.childImageSharp.fluid
        return (
          <div>
            <Image fluid={thumbnail} alt="" />
          </div>
        )
      })}
    </div>
  )
}

export default BlogIndex

まとめ

以上です。

誰かの参考になれば幸いです。

フィードバックのお願い
この記事のフィードバックがありましたらYoutubeの適当な動画にコメントしていただいたり、お問い合わせからご連絡ください。