gatsby-plugin-satorareを使ってGatsbyブログのOG画像をJSX構文で記事ごとに生成してみた
(gatsby-plugin-satorare
の開発者によるステマ記事です)
はじめに
最近gatsby-plugin-satorare
というGatsbyプラグインが公開された。このプラグインでは内部でvercel/satori
が使用されており、OG画像のテンプレートをJSX構文で記述して作成できるようだ。
今回はこのプラグインを使って記事ごとのOG画像を作成してみる。
完成物
作成したOG画像を最初に紹介しておく。
これが記事用の画像。
記事用とは別にサイトのOG画像も作成できるので以下のようなものを作成した。
作り方
パッケージをインストール
まずはインストール。現時点での最新バージョンは0.1.1
だ。
npm i -D gatsby-plugin-satorare
パッケージの設定
gatsby-config.js
内にパッケージの設定を記述する。必須となる設定はpath
のみで、ここにOG画像の元となるJSX/TSXファイルのパスを設定する。
その他の設定としては、画像のサイズやフォントなどが設定可能だ。詳しくはREADMEに記載があるので参照されたい。
{
resolve: `gatsby-plugin-satorare`,
options: {
path: `${__dirname}/src/components/OgImage.tsx`,
}
}
JSX構文で画像のテンプレートを作成
先ほど指定したpath
のファイル内でOG画像のテンプレートをJSX構文で作成していく。このファイル内ではReactElement
を返す関数をデフォルトexportする必要がある。
この関数の引数にはNode
を受け取ることができ、そのinternal.type
によって必要なOG画像を作成していく。デフォルトの設定ではMarkdownRemark
とSite
の2種類のNode
を受け取ることができ、それぞれ記事用とサイト全体用のOG画像に利用する。
自分が作成した画像テンプレートは以下。作成する際はVercelのPlaygroudを使うと作成される画像をプレビューしながらテンプレートを作成することができて便利だった。
import { Node } from 'gatsby'
type Frontmatter = {
title: string
tags: string[]
}
export default function(node: Node) {
if (node.internal.type === 'MarkdownRemark') {
const frontmatter = node.frontmatter as Frontmatter
const title = frontmatter.title
const tags = frontmatter.tags
return (
<div
style={{
display: 'flex',
padding: 48,
height: '100%',
backgroundColor: '#2e3440',
}}
>
<div
style={{
height: '100%',
width: '100%',
display: 'flex',
justifyContent: 'space-between',
flexDirection: 'column',
backgroundColor: 'white',
color: '#000000d1',
padding: 48,
borderRadius: 12,
}}
>
<div
style={{
display: 'flex',
flexDirection: 'column',
}}
>
<div style={{ fontSize: 64, maxWidth: 1000, fontWeight: 600 }}>{title}</div>
<div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', marginTop: 16, gap: 16 }}>
{tags.map((tag, i) => (
<div
key={i}
style={{
fontSize: 32,
fontWeight: 400,
backgroundColor: 'rgb(229,231,235)',
padding: '8px 24px',
borderRadius: 200,
}}
>
{tag}
</div>
))}
</div>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 16 }}>
<div style={{ fontSize: 48, fontWeight: 400, display: 'flex', alignItems: 'center' }}>
<img
src="https://avatars.githubusercontent.com/u/44517313?v=4"
width={72}
height={72}
style={{ borderRadius: '50%', marginRight: 16 }}
/>
okaryo
</div>
</div>
</div>
</div>
)
} else {
return (
<div
style={{
display: 'flex',
padding: 48,
height: '100%',
backgroundColor: '#2e3440',
}}
>
<div
style={{
height: '100%',
width: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white',
color: '#000000d1',
borderRadius: 12,
fontSize: 144,
fontWeight: 600,
}}
>
<img
src="https://avatars.githubusercontent.com/u/44517313?v=4"
width={144}
height={144}
style={{ borderRadius: '50%', marginRight: 16 }}
/>
okaryo.log
</div>
</div>
)
}
}
GraphQLからOG画像を取得
これでビルドして開発用のGraphQLページで確認してみると、以下のフィールドが追加されているはずだ。
allMarkdownRemarkOgImage
allSiteOgImage
markdownRemarkOgImage
siteOgImage
これを使ってOG画像を取得していくが、その前に準備が必要になる。記事と記事ごとのOG画像であるmarkdownRemarkOgImage
を紐付けるには、記事のNodeIDが必要になる。GraphQLのクエリ中で記事のIDを取得できるようにするために記事ページを作成するcreatePage
のcontext
に記事のNodeIDを追加しておく。
// gatsby-node.js
createPage({
path: post.node.fields.slug,
component: blogPost,
context: {
id: post.node.id, // これを追加
slug: post.node.fields.slug,
previous,
next,
},
})
こうすることでクエリ中で($id: String!)
として記事のIDが取得できる。これとmarkdownRemarkOgImage
の親NodeのIDを紐付けることで記事ごとのOG画像のパスを取得することができる。サイト全体のOG画像も以下のようなクエリで取得可能だ。
// query
`
query BlogPostQuery($id: String!) {
markdownRemarkOgImage(parent: {id: {eq: $id}}) {
attributes {
publicURL
}
}
siteOgImage {
attributes {
publicURL
}
}
}
`
// result
{
"data": {
"markdownRemarkOgImage": {
"attributes": {
"publicURL": "/static/8d5a6b2a951985acb20f041bf8f52e61/8d5a6b2a951985acb20f041bf8f52e61.png"
}
},
"siteOgImage": {
"attributes": {
"publicURL": "/static/1d3db0d32c1e9ff61a30f15b2b9b6a2d/1d3db0d32c1e9ff61a30f15b2b9b6a2d.png"
}
}
}
}
og:image
に画像を設定
最後に上記で取得したOG画像のパスをメタタグに設定すれば完了だ。
const yourSite = 'https://example.com'
const ogImagePath = data.markdownRemarkOgImage.attributes.publicURL
return (
<>
{/* other meta tags */}
<meta property='og:image' content={yourSite + ogImagePath} />
{/* other meta tags */}
<>
)
おわり
簡単に記事ごとのOG画像を作成できたし、しかもそれをJSX構文で記述できるのでかなり体験が良かった。
気になった方は是非使ってみてほしい。気に入った方はぜひGitHubでスターをつけてほしい。