エッジで動的にOG画像を生成できる@vercel/ogを触ってみた

2022/10/11に公開

はじめに

Vercelからエッジで動的にOG画像を生成できる@vercel/ogが発表されました。
https://vercel.com/blog/introducing-vercel-og-image-generation-fast-dynamic-social-card-images

早速触ってみたいと思います。

@vercel/ogとは

Vercel Edge Functionsを使用して動的にOG画像を生成してくれます。

OG画像はHTMLとCSS(というかJSX)を使用して定義することができるので、特にReactエンジニアは非常に簡単にOG画像を定義できます。すごい。

コアエンジンにはSatoriというHTMLとCSSをSVGに変換するライブラリが使われています。

環境

触ってみた

実装は非常に簡単でAPI Routesにruntime: 'experimental-edge'のエンドポイントを作成するだけでOKです。

pages/api/og.tsx
import { ImageResponse } from '@vercel/og'

export const config = {
  runtime: 'experimental-edge',
}

export default function handler() {
  return new ImageResponse(
    (
      <div
        style={{
          display: 'flex',
          justifyContent: 'center',
          alignItems: 'center',
          width: '100%',
          height: '100%',
          backgroundColor: 'white',
          fontSize: '128px',
        }}
      >
        Hello world!
      </div>
    )
  )
}

これだけで開発サーバーを起動して http://localhost:3000/api/og にアクセスするとOG画像を確認できます。

あとは任意のページにmetaタグを配置すればOKです。

import Head from 'next/head'

<Head>
  <title>Hello world</title>
  <meta
    key="og:image"
    property="og:image"
    content="https://example.com/api/og"
  />
</Head>

動的にタイトルを挿入する

https://example.com/api/og?title=hogeのようにクエリパラメーターを使用することで動的にタイトルを挿入することができます。

pages/api/og.tsx
import { ImageResponse } from '@vercel/og'
import { NextRequest } from 'next/server'

export const config = {
  runtime: 'experimental-edge',
}

export default function handler(req: NextRequest) {
  try {
    const { searchParams } = new URL(req.url)
    const title = searchParams.get('title')?.slice(0, 100) ?? 'Hello world!'

    return new ImageResponse(
      (
        <div
          style={{
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            width: '100%',
            height: '100%',
            backgroundColor: 'white',
            fontSize: '128px',
          }}
        >
          {title}
        </div>
      )
    )
  } catch (e) {
    if (e instanceof Error) {
      console.error(e.message)
    }
    return new Response(`Failed to generate the image`, {
      status: 500,
    })
  }
}

Google Fontsを使用する

Google Fontsに限らず、ttf, otf, woff形式のフォントファイルがサポートされています。

Google Fontsの場合は各フォントのページのDownload familyでダウンロードしたフォントファイルをassets配下に格納してコードから読み込むことで使用することができます。

RobotoのBold 700を使用したい場合は以下のようにします(事前にフォントファイルをダウンロードしてRoboto-Bold.ttfassets配下に格納しておいてください)。

pages/api/og.tsx
import { ImageResponse } from '@vercel/og'

export const config = {
  runtime: 'experimental-edge',
}

export default async function handler() {
  const fontData = await fetch(
    new URL('../../assets/Roboto-Bold.ttf', import.meta.url)
  ).then((res) => res.arrayBuffer())

  return new ImageResponse(
    (
      <div
        style={{
          display: 'flex',
          justifyContent: 'center',
          alignItems: 'center',
          width: '100%',
          height: '100%',
          backgroundColor: 'white',
          fontFamily: '"Roboto"',
          fontWeight: 'bold',
          fontSize: '128px',
        }}
      >
        Hello world!
      </div>
    ),
    {
      fonts: [
        {
          name: 'Roboto',
          data: fontData,
          weight: 700,
          style: 'normal',
        },
      ],
    }
  )
}

おわりに

@vercel/ogを触ってみました。

@vercel/og+Vercel Edge Functions+Next.jsの組み合わせであれば非常に簡単に動的にOG画像を生成できて驚きました。

エッジではなくNode.jsで使用したい場合はSatoriをそのまま使用することもできそうですし、これから盛り上がっていきそうだなと思いました。

また、公式ドキュメントに使用例やAPIの仕様が記載されているのでそちらも確認してみてください。
https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation
https://vercel.com/docs/concepts/functions/edge-functions/og-image-examples
https://vercel.com/docs/concepts/functions/edge-functions/og-image-api

株式会社モニクル

Discussion