Next.jsでOpenGraph画像を自動生成する

2021年1月28日

  • Next.js
  • React
  • JavaScript

Next.js でブログなどをSSGするときに、OpenGraph 用の画像を自動生成してくれる方法を解説します。

画像生成用のプロジェクトを作成#

まず、画像生成用ののプロジェクトを作成します。もちろん、既存のプロジェクトを使うこともできます。 こちらも Next.js を使って作成していきます。

セットアップ#

terminal
1npx create-next-app og-image

また、今回はスタイリングのために chakra-ui を使っていきます。 Next.js プロジェクトに chakra-ui をインストールする方法はこちらを参考にしてください。

ページを作成する#

jsx
1/* pages/index.js */
2
3import { chakra, Heading, HStack } from '@chakra-ui/react';
4import { useRouter } from 'next/router';
5import Image from 'next/image';
6
7export default function Home() {
8 const router = useRouter()
9 const searchParams = new URLSearchParams(router.asPath.split(/\?/)[1]);
10 const title = searchParams.get('title');
11
12 return (
13 <>
14 <chakra.div
15 position="relative"
16 display="flex"
17 flexDirection="column"
18 width={1200}
19 height={630}
20 p={16}
21 justifyContent="space-between"
22 alignItems="center"
23 borderWidth="2rem"
24 borderColor="gray.600"
25 >
26 <div/>
27 <Heading px="4rem" textAlign="center" fontSize="5rem">
28 {title}
29 </Heading>
30 <HStack spacing="1rem">
31 <chakra.div
32 position="relative"
33 width="8rem"
34 height="8rem"
35 borderRadius="50%"
36 overflow="hidden"
37 >
38 <Image src="/profile.png" layout="fill" objectFit="contain" />
39 </chakra.div>
40 <Heading fontSize="2rem">so99ynoodles</Heading>
41 </HStack>
42 </chakra.div>
43 </>
44 );
45}

URLの query-stringtitle を渡すことで動的に画像が作れるようにしました。 また、画像のページは1200 x 630 になるようにしました。用途に応じて適宜最適化して使ってください。

画像生成用プロジェクト

localhost:3000/?title=Next.jsでOpenGraph画像を自動生成する にアクセスすると、以上のような画面ができました。 Vercel などにデプロイしたら最初のステップは完了です。

ビルド時に上記のページにアクセスし、OpenGraph画像を取得#

SSGを行う Next.js プロジェクトでOpenGraph 画像を自動生成する関数を書いていきます。

関数を作成#

js
1/* utils/openGraphImage.js */
2
3import fs from 'fs';
4import { createHash } from 'crypto';
5import { chromium } from 'playwright';
6
7export async function getOpenGraphImage(path) {
8
9 /* productionのみで使う */
10 if (process.env.NODE_ENV === 'development') {
11 return;
12 }
13
14 /* 自分のプロジェクトURLに変更してください */
15 const baseUrl = 'https://example.og.com'
16 const url = `${baseUrl}${path}`;
17 const hash = createHash('md5').update(url).digest('hex');
18
19 const ogImageDir = `./public/images/og`;
20 const imagePath = `${ogImageDir}/${hash}.png`;
21 const publicPath = `${process.env.SITE_URL}/images/og/${hash}.png`;
22
23 try {
24 fs.statSync(imagePath);
25 return publicPath;
26 } catch (e) {
27 console.log(`generating og image for ${path}`);
28 }
29
30 const browser = await chromium.launch({ headless: true });
31 const page = await browser.newPage();
32 await page.setViewportSize({ width: 1200, height: 630 });
33 await page.goto(url, { waitUntil: 'networkidle' });
34 const buffer = await page.screenshot({ type: 'png' });
35 await browser.close();
36
37 fs.mkdirSync(ogImageDir, { recursive: true });
38 fs.writeFileSync(imagePath, buffer);
39
40 return publicPath;
41}

getOpenGraphImage でやっているを簡単に説明すると以下になります。


  1. playwright を使って Chrominium ブラウザーでページにアクセス
  2. ページのスクリーンショットを /public/images/og に保存
  3. 保存された画像のproduction用URLを返す

getStaticProps で関数を使用#

getOpenGraphImage 関数を getStaticProps で使い、OpenGraph 画像を自動生成します。

jsx
1/* pages/blog/[post].js */
2
3export const getStaticProps = async ({ params }) => {
4 const { post } = params;
5 const { frontmatter, source } = await getPost(post);
6 const openGraphImage = await getOpenGraphImage(`/?title=${frontmatter.title}`);
7 return {
8 props: {
9 frontmatter,
10 source,
11 openGraphImage,
12 }
13 };
14};

これでビルド時に OpenGraph 画像が自動生成されるようになりました。

Next.js にSEO情報を適用#

最後に、生成した OpenGraph 画像をSEOに適用させます。 next-seo を使って簡単に実装できます。

SEOを設定する#

terminal
1npm install next-seo
jsx
1/* pages/blog/[post].js */
2import Head from 'next/head';
3import { NextSeo } from 'next-seo';
4
5export default function BlogPost({ frontmatter, source, openGraphImage }) {
6 const { title, description, slug } = frontmatter;
7 return (
8 <Layout>
9 <Head>
10 <NextSeo
11 title={title}
12 description={description}
13 openGraph={{
14 title,
15 description,
16 url: `${process.env.SITE_URL}/${slug}`,
17 images: [{
18 url: openGraphImage
19 }]
20 }}
21 />
22 </Head>
23 {source}
24 </Layout>
25 )
26}

文字化け対策#

playwrightOpenGraph 画像生成のページに入ると、日本語が文字化けになってしまいました。 対策として日本語に対応したフォントを読み込んで適用させました。簡単に使える Google Fonts を使用しました。

jsx
1/* pages/index.js */
2
3import GoogleFonts from 'next-google-fonts';
4
5export default function Home() {
6 ...
7 <GoogleFonts href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;500;700;900&display=swap" />
8 ...
9 <Heading fontFamily="Noto Sans JP" px="4rem" textAlign="center" fontSize="5rem">
10 {title}
11 </Heading>
12 ...
13}