【Gatsby.js】マークダウンで書いた記事にサムネイルを表示する方法
いつもご利用ありがとうございます。
この記事には広告が掲載されており、その広告費によって運営しています。
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 などを無しにして何とか絶対パスで書けないか、試したりなどしたけど上手くいかなかったので、このやり方で落ち着いてます。
もし自分の見落としだったら教えていただけると嬉しいです。
ちなみに、この書き方はここに書かれています。
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
}
}
}
}
}
}
}
`
出力結果を見る
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-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
まとめ
以上です。
誰かの参考になれば幸いです。