Next.jsのImage Generationを利用して、動的にOG画像を作成する

このチュートリアルでは、Next.jsの Image Generation を利用して、動的にOG画像を作成する手順を紹介します。

記事内で使用している主なソフトウェアのバージョン

  • Next.js(next): 13.3.0

前提条件

  1. Next.jsの13.3.0以上を利用していること
  2. Next.jsの API Routes について理解していること
  3. Vercelへのデプロイについて理解していること
  4. OG画像を利用するWebサイトを作成していること

概要

Next.jsの Image Generation を利用して、OG画像を生成するAPIを作成します。
ImageResponseEdge Runtime を利用します。

リクエストのクエリパラメータにタイトルを付け、タイトルをOG画像に反映するようにします。

以下のようなOG画像を作成できます。
「Fictitious Communityが 〜 主催したか」の部分がタイトルとなります。

og.png

1. OG画像を生成するAPIを作成する

1-1. pages/api/og.tsx の作成

OG画像を生成するAPIにアクセスすると、画像を返却するようにします。
また、クエリパラメータに title をつけると、その値をもとにOG画像を作成できるようにします。
ここでは、エンドポイントが /api/og となるように、pages/api/og.tsx というファイルを用意します。この処理では、以下のことを行います。

  • Edge Runtime を利用するために、Edge API Routes として、configの runtimeedge を指定する
  • クエリパラメータの title の値を利用して、動的にタイトルを表示する
  • HTMLとCSSでOG画像のデザインをマークアップする
  • 背景画像として、以下の画像を使う(以下のコードでは https://og-image-example.vercel.app/bg.png から画像が取得できる想定とします。背景画像が不要な場合は、backgroundImage のプロパティを削除して下さい)

bg.png

// pages/api/og.tsx

import { ImageResponse, NextRequest } from "next/server";

export const config = {
  runtime: "edge",
};

export default function handler(req: NextRequest) {
  try {
    const { searchParams } = new URL(req.url);

    const hasTitle = searchParams.has("title");
    const title = hasTitle
      ? searchParams.get("title")?.slice(0, 100)
      : "My default title";

    return new ImageResponse(
      (
        <div
          style={{
            backgroundImage: "url(https://og-image-example.vercel.app/bg.png)",
            backgroundColor: "#fff",
            backgroundSize: "100% 100%",
            height: "100%",
            width: "100%",
            display: "flex",
            textAlign: "left",
            alignItems: "flex-start",
            justifyContent: "center",
            flexDirection: "column",
            flexWrap: "nowrap",
          }}
        >
          <div
            style={{
              width: "100%",
              fontSize: 60,
              fontStyle: "normal",
              fontWeight: "bold",
              color: "#000",
              padding: "0 120px",
              lineHeight: 1.3,
              marginBottom: "30px",
              wordWrap: "break-word",
            }}
          >
            {title}
          </div>
          <div
            style={{
              width: "100%",
              fontSize: 40,
              fontStyle: "normal",
              fontWeight: "bold",
              color: "#000",
              padding: "0 120px",
              lineHeight: 1.3,
            }}
          >
            ✏️ OG Image Examples
          </div>
        </div>
      ),
      {
        width: 1200,
        height: 630,
      }
    );
  } catch (e: any) {
    console.log(`${e.message}`);
    return new Response(`Failed to generate the image`, {
      status: 500,
    });
  }
}

マークアップから画像への変換には、Satori というライブラリが使用されています。通常のブラウザとは対応しているCSSプロパティが異なるため注意が必要です。詳細は Satori のドキュメントをご確認ください。

1-2. ローカル環境での確認

ローカル環境で正しく実行されるか、確認してみましょう。以下のURLにアクセスします。

http://localhost:3000/api/og?title=テスト

以下のように表示されれば成功です。

test.png

1-3. 本番環境へのデプロイ

ローカル環境で確認できたら、Vercelにデプロイしておきます。

2. APIを呼び出し、OG画像を設定する

次に、OG画像を設定したいサイトから、1で作成したAPIを呼び出すようにします。
※以下、1-3でデプロイしたAPIのエンドポイントは https://og-image-example.vercel.app/api/og と想定します。

<meta> タグの中にOG画像のURLを設定しましょう。

<head>
  <title>The post's title</title>
  <meta
    property="og:image"
    content="https://og-image-example.vercel.app/api/og?title=my post title"
  />
</head>

Newt-Inc/newt-blog-starter-nextjs から呼び出す場合、以下のようになります。

// pages/article/[slug].tsx

//(省略)

export default function ArticlePage({
  app,
  currentArticle,
}: {
  app: AppMeta;
  currentArticle: (Content & Article) | null;
}) {
  //(省略)

  const ogImage = useMemo(() => {
    return `https://og-image-example.vercel.app/api/og?title=${currentArticle.title}`;
  }, [currentArticle.title]);

  //(省略)

  return (
    <Layout app={app}>
      <Head>
        <!--(省略)-->
        <meta property="og:image" content={ogImage} />
        <!--(省略)-->
      </Head>
      <!--(省略)-->
    </Layout>
  );
}

コードを修正したら、デプロイを行い、本番環境に反映します。

以上で、設定は終了です。
これで、動的にOG画像を作成できるようになりました。

og2.jpg

Newt Made in Newt