はじめに
Next.js 製のこのサイトに動的 OGP を実装した。それに伴い行ったことなどを残しておく。
方針
Vercel でホスティングしている Next.js 製サイトに動的 OGP を実装する方法についてはいくつかある。
上記のライブラリがググると上の方に出てくるじゃないだろうか。今回は中でも情報が多く、割と一般的(?)である vercel/og-image を使うことにした。
vercel/og-image を fork してローカルで立ち上げる
細かい部分をカスタマイズすることになるので、先んじて下記のリポジトリを fork しておく。
README.md のデプロイボタンからワンクリックで Vercel へデプロイできるようになっているのだが、無料の Hobby Plan ではこのままだとデプロイできないので以下に修正する。
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"regions": ["hnd1"],
"functions": {
"api/**": {
"memory": 1024
}
},
"rewrites": [
{ "source": "/(.+)", "destination": "/api" }
]
}
Vercel は AWS で作られているらしく、できればより読者が多い日本の AWS リージョンでホスティングしてほしいので、 region も修正してみた。気になる人は Vercel と AWS のリージョンの対応表1を参照してみてほしい。
また、これから OGP 画像をカスタマイズしていく訳だが、ローカルで確認しながら修正していきたい。それには Vercel CLI を使うとローカルで Serverless Function を含んだコードを実行できるので非常に便利だ。導入は下記に書いたが、3 行コマンドを実行するだけで完了する。
# インストールがまだであればインストールする
$ npm install -g vercel
# 初回は Vercel アカウントと CLI の紐付けがされていないので認証を求められる
# コマンドを実行しているパスのプロジェクトが Vercel にデプロイされる
$ vercel
# ビルドを実行し、localhost でサーバを起動
$ vercel dev
日本語に対応させる
まずは、デフォルトだと日本語に対応していないので日本語対応させる。
function getCss(theme: string, fontSize: string) {
// 省略
return `
@import url('https://fonts.googleapis.com/css?family=Noto+Sans+JP&display=swap');
..
.heading {
font-family: 'Noto Sans JP', sans-serif;
..
}`;
}
上の例では、Noto Sans JP をインポートして、CSS を適用した。もし使いたいフォントがあれば同様に URL で指定してあげれば良いと思う。
ここまでで一旦デプロイすると下記のようになり、無事日本語が表示できるようになる。

デザインを調整する
ここまでできたら HTML, CSS を修正して OGP のデザインを微調整するだけだ。僕は、技術ブログサービスで有名な Qiita, はてブ、Zenn あたりを参考に記事のタイトルとサイト名を OGP 画像に埋め込んだ。

SNS のタイムラインなどでシェアされた場合、ユーザに視覚的に訴えることができ、少しでもインプレッションの向上に寄与できれば嬉しい。
OGP 画像として使いたいサイトで meta タグを変更する
最後に、実際に OGP 画像を使いたいこのサイトから使える用に meta タグを修正する。
このサイトは Next.js で作られていて、SEO に関する meta タグ類は SEO コンポーネントにまとめている。
interface SEOProps {
title: string
description: string
ogType: string
ogImage: string
twImage: string
}
const SEO = ({
title,
description,
ogType,
ogImage,
twImage
}: SEOProps) => {
if (ogType === 'article') {
const dynamicOgImage = `${process.env.NEXT_PUBLIC_OG_IMAGE_DOMAIN}/${encodeURIComponent(title)}`
ogImage = dynamicOgImage
twImage = dynamicOgImage
}
return (
<Head>
<title>{title}</title>
{/* OGP 以外の meta タグは省略 */}
<meta property="og:type" content={ogType} />
<meta property="og:image" content={ogImage} key={ogImage} />
<meta name="twitter:image" content={twImage} />
<meta name="twitter:card" content='summary_large_image' />
</Head>
)
}
コメントアウトにも書いている通り OGP 以外の meta タグを省略して書くと上記のようになる。
ブログ記事の pages/blog/[...slug].tsx からこのコンポーネントを呼び出す際にだけ props ogType='article' を渡して上げれば良い。また、NEXT_PUBLIC_OG_IMAGE_DOMAIN には vercel/og-image から fork してデプロイした URL を .env に設定しておけば OK だ。
まとめ
今回は Next.js で作られたこのサイトに動的 OGP を実装してみた。
Vercel についてよく知らなかったけど、内部的に AWS が使われていたり、CLI が便利だったりといろいろと学びがあった。また動的な OGP 画像の作り方もたくさんのブログ記事を読む過程でかなり勉強になった。
今後もし、取り組むとしたら AWS Lambda などを使って一から同様の仕組みを作ってみたい。
参考
Footnotes
Next.js のサイトに Google Tag Manager 経由でGoogle Analytics(GA4)を導入する
Kubernetes 技術者認定 CKA/CKAD を取得したので振り返る