TL;DR
Open Graph プロトコルと @vercel/og ライブラリを使用して、ソーシャルメディア画像生成の最適化方法を解説します。動的な Open Graph(OG)画像を生成するために、Vercel の @vercel/og
ライブラリを使用して、Vercel Edge Functions を用いてソーシャルカード画像を計算・生成することができます。
つまり、分かりやすくいうと、CSS とテキストを使って画像を自動生成できる ということです。今までのようにアイキャッチ画像や OGP 画像を記事ごとに作る必要が無くなるので、とても便利です。
利点
画像生成に必要なコード量が少ないため、Edge Functions はほぼ瞬時に開始することができます。これにより、画像生成プロセスが迅速に行われ、Open Graph Debugger のようなツールによって認識されます。
HTML と CSS を使用して画像を定義し、ライブラリはマークアップから動的に画像を生成します。
@vercel/og は、エッジで計算済みの画像をキャッシュするための適切なヘッダーを自動的に追加して、コストの削減と再計算の軽減ができるそうです。
サポートされている機能
- flexbox や絶対位置付けを含む基本的な CSS レイアウト
- カスタムフォント、テキストの折り返し、中央揃え、ネストされた画像
- Google Fonts からフォントのサブセット文字をダウンロードする能力
- Vercel でデプロイされた任意のフレームワークやアプリケーションと互換性
はじめに
最初に @vercel/og
をインストールします。
npm i @vercel/og
Open Graph (OG) Image Generation | Vercel Docs を参考に、/pages/api の下に og.tsx を追加して API エンドポイントを作成します。
pages/api/og.tsx
import { ImageResponse } from '@vercel/og'
import { NextRequest } from 'next/server'
import Image from 'next/image'
export const config = {
runtime: 'edge',
}
export default function handler(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
// ?title=<title>
const hasTitle = searchParams.has('title')
const title = hasTitle ? searchParams.get('title')?.slice(0, 100) : 'My default title'
return new ImageResponse(
(
<div
style={{
backgroundColor: 'black',
backgroundSize: '150px 150px',
height: '100%',
width: '100%',
display: 'flex',
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
flexWrap: 'nowrap',
}}
>
<div
style={{
fontSize: 60,
fontStyle: 'normal',
letterSpacing: '-0.025em',
color: 'white',
marginTop: 30,
padding: '0 120px',
lineHeight: 1.4,
whiteSpace: 'pre-wrap',
}}
>
{title}
</div>
<div
style={{
marginTop: 30,
display: 'flex',
// alignItems: 'center',
justifyContent: 'center',
justifyItems: 'center',
}}
>
<img alt="" height={75} src="http://localhost:3000/logo.png" style={{ margin: '0 30px' }} width={320} />
</div>
</div>
),
{
width: 1200,
height: 630,
}
)
} catch (e: any) {
console.log(`${e.message}`)
return new Response(`Failed to generate the image`, {
status: 500,
})
}
}
呼び出し
process.env.NODE_ENV
を使って現在の環境が開発(ローカル)か本番かを判断することができます。環境によって URL を動的に切り替えるためのコードは以下のようになります:
<img src={`${process.env.BASE_URL || 'http://localhost:3000'}/api/og?title=${postData.id}`} alt="" />
Vercel において環境変数を設定するには、以下の手順を実施します:
- Vercel ダッシュボードにログインします。
- 対象のプロジェクトを選択します。
- プロジェクトダッシュボードの左側のメニューで、"Settings" をクリックします。
- "Settings" メニューの中から "Environment Variables" を選択します。
- "Add" ボタンをクリックします。
- "Name" フィールドに環境変数名(例:
BASE_URL
)を入力し、"Value" フィールドに対応する値(例:https://あなたのドメイン
)を入力します。 - "Add" ボタンをクリックして環境変数を保存します。
これで、環境変数は次回のデプロイ時に適用されます。
これにより、ローカル環境では'http://localhost:3000'
が使われ、Vercel では設定したBASE_URL
が使われます。
ImageResponse コンストラクタ
@vercel/og
で、うまく表示できないときは、ImageResponse コンストラクタを使うとよさそうです。
Next.js のImageResponse
コンストラクタは、JSX と CSS を使用して動的な画像を生成するためのものです。これは、Open Graph イメージや Twitter カードなどのソーシャルメディアの画像を生成するのに便利です。
以下のようにImageResponse
をインポートし、新しいImageResponse
オブジェクトを生成することができます:
import { ImageResponse } from 'next/server'
new ImageResponse(
element: ReactElement,
options: {
width?: number = 1200
height?: number = 630
emoji?: 'twemoji' | 'blobmoji' | 'noto' | 'openmoji' = 'twemoji',
fonts?: {
name: string,
data: ArrayBuffer,
weight: number,
style: 'normal' | 'italic'
}[]
debug?: boolean = false
// Options that will be passed to the HTTP response
status?: number = 200
statusText?: string
headers?: Record<string, string>
},
)
Functions: ImageResponse | Next.js
この構造体には、以下のオプションが用意されています。
オプション | データ型 | デフォルト値 | 説明 |
---|---|---|---|
element | ReactElement | - | 描画する ReactElement |
width | number | 1200 | 画像の幅 |
height | number | 630 | 画像の高さ |
emoji | string ('twemoji' | 'blobmoji' | 'noto' | 'openmoji') | 'twemoji' | 使用する絵文字のセット |
fonts | Array | - | 画像内で使用するカスタムフォントの配列。各フォントは、フォント名、フォントデータ(ArrayBuffer)、フォントの重み、およびスタイル('normal'または'italic')を指定します |
debug | boolean | false | デバッグモードを有効にするかどうか |
status | number | 200 | HTTP レスポンスのステータスコード |
statusText | string | - | HTTP レスポンスのステータステキスト |
headers | Record<string, string> | - | HTTP レスポンスに追加するヘッダーのレコード |