🔫

独り言形式で綴る「OGP & SSR」

2022/05/17に公開

OGP画像を表示させたい

「よし、Webサービスを作ったぞ」
「プログラミングに関する記事を投稿できるWebサービスだ」
「このサイトの記事をTwitterとかでシェアしてもらって、人気が出るといいな」
「シェアしてもらったときに、やっぱりOGP画像が表示された方がいいよな」
「よくあるような、記事のタイトルとかサイト名が入ったサムネ画像みたいなのを表示したいな」
「よし、そのためには、HTMLのmetaタグに、OGPの情報が入るようにしないとな」

Next.jsでheadタグの中をいじる

「今回のWebサービスでは、フロント部分をNext.js[1]で実装したから」
「Next.jsでheadタグの中をいじって、metaタグにOGP情報を埋め込もう」

/pages/articles/[id].jsx
<Head>
	<meta property="og:title" content="記事タイトル" />
	<meta property="og:description" content="記事の説明" />
	<meta property="og:image" content="OGP画像のURL" />
	<meta name="twitter:card" content="summary_large_image" />
</Head>

「よし、metaタグはこんな感じだな」
記事タイトルOGP画像のURLは、APIから取得した文字列を入れるようにしておこう」
「各記事ごとに、動的に変えたいからな」
SWRでAPIから取得したデータは、apiDataという名前の変数に入っているから・・・」

/pages/articles/[id].jsx
<Head>
	<meta property="og:title" content={apiData.title} />
	<meta property="og:description" content={apiData.description} />
	<meta property="og:image" content={apiData.thumbnailUrl} />
	<meta name="twitter:card" content="summary_large_image" />
</Head>

「↑こんな感じだな」
「よし、それじゃあサイトをデプロイし直して・・・」
「試しにTwitterで記事をシェアしてみよう」

表示されない

「あれ、OGPのためのmetaタグを書いたはずなのに、OGP画像が表示されないぞ」
「ネットで原因を調べてみるか・・・」

Twitterのクローラーは、SPAを解釈できないらしい

「ふむふむ、どうやら」
SWRを使ってAPIから取得した記事の情報を、metaタグに入れる・・・」
「これではダメみたいだ」

Twitter「お、URLを含んだツイートがされたぞ」
Twitter「じゃあ、そのサイトを見に行って、OGP画像があったら、ツイート上に表示しよう」
Twitter「お、このサイトだな」
Twitter「うーん・・・なんだろう、難しいJavaScriptやめてもらっていいっすか?」
Twitter「ええと、OGP情報は・・・無し!」
※イメージです

「↑こんな感じになってしまうみたいだ」
「Twitterのクローラーは、JavaScriptを完璧に解釈できる訳ではないから」
「SPA的なクライアントサイドの手法metaタグを埋め込んでも、うまく表示されないらしい」

SSR(Server-Side Rendering)をしないといけない

「クローラーがHTMLを読み込んでから、JavaScriptでmetaタグをいじるのではダメってことだな」
「クローラーがHTMLを読み込んだ時点で、metaタグに情報が入っていないとダメってことか」
「つまりmetaタグは、サーバサイドで書き込んでおく必要があるんだな」
「だから、サーバサイド・レンダリングというんだな」

Next.jsの場合、getServerSidePropsを使う

「どうやら、記事ページのjsxファイル内に」
getServerSidePropsという関数を書いて、exportすればいいみたいだ」

/pages/articles/[id].jsx
export async function getServerSideProps({ query }) {
  // APIからデータを取得
  const res = await fetch(`https://.../api/ogp/articles/${query.id}`)
  const ogpData = await res.json()

  // それをpropsに入れて、オブジェクトとして返す
  return { props: { ogpData } }
}

「よし、こうだな」
metaタグの方は...」

/pages/articles/[id].jsx
<Head>
	<meta property="og:title" content={ogpData.title} />
	<meta property="og:description" content={ogpData.description} />
	<meta property="og:image" content={ogpData.thumbnailUrl} />
	<meta name="twitter:card" content="summary_large_image" />
</Head>

「↑こうだな」
「よし、もう一度デプロイし直して」
「試しに記事をシェアしてみよう」

表示された

「よし、OGP画像が表示されたぞ」
「目的達成だ!」

※確認できない場合は、Twitterカードのキャッシュをクリアしてみましょう。
※というか、TwitterのCard Validator上で確認すればいいみたいです。

まとめ

  • Twitterのクローラーは、SPAを解釈できない
    • クライアントサイドでmetaタグを書いてもダメ
  • クローラーがHTMLを取得した時点で、metaタグにOGP情報が書いてないとダメ
    • 各記事ごとに動的にOGP情報を埋め込みたい場合には、サーバ側での処理が必要
  • Next.jsではgetServerSidePropsを使用して実装する

注意点

  • サーバ側での処理が必要なため、ホスティングサービスの選定時に注意が必要
    • ホスティング先をVercelAWS Amplify Consoleにしておくとやりやすい
    • Serverless Next.js Componentを使用しても可能
    • どちらも内部的にはAWSのLambda@Edgeを使用しているらしい

他のやり方

  • SG(静的生成)
    • デプロイ前にhtmlファイルを静的生成するタイミングで、APIと通信してmetaタグを書いておければ、SSRする必要はありません。要件によりけりですね。
脚注
  1. React製のフレームワークです。 ↩︎

株式会社ゆめみ

Discussion