🖼️
Vite + React + SSRしてページごとOGPを有効にする
- Next.jsってありがたいの極みだなと思いました
- 前日談: React でp5.jsのギャラリーサイト作る( + Vite, React Router, Vercel )
やりたいこと
- 1ページごとに異なるOGPを表示できたい
- ページコンテンツはp5.jsでコンテンツ作る時にどのみちソースコードを触るので、OGPの内容とかは手動でセットで良い。
- 元はVite + React + React Router
方向性
- React Routerはアンインストールします
- vite-plugin-ssrを導入します
やっていく
vite-plugin-ssrの導入
- Add to existing app | vite-plugin-ssrを参考に進めていきます。
-
npm install vite-plugin-ssr
をしたら手順1へ。手順2は任意なので今回は飛ばします。 - 私はReact + tsなので、vite-plugin-ssr/boilerplates/boilerplate-react-ts at main · brillout/vite-plugin-ssrを参考にします。
-
renderer
はほぼそのまま導入。 -
renderer/PageShell.tsx
のContent
がページコンテンツになる ≒ その外側はガワでしかないので、よしなに削ります。私はこんな感じになった → creative-gallery/PageShell.tsx at main · thetalemon/creative-gallery - pagesはこんな感じ。
p5.tsx
の理由は後述します - これで起動したら多分起動できる。
react-roouter
を使ってた人はApp.tsx
もindex.tsx
も削除してOK。
client-onlyしたい
- p5.jsはwindowに依存するので、クライアンドサイドでのみレンダリングされる必要がある
- 公式にClient-only Components | vite-plugin-ssrというページがあるが、公式の導く通りに
React.lazy
を導入してもClient-onlyにならなかった -
typeof window !==
undefined``をしてからReact.lazy
でimport
にした。- どれか抜いても動きそうな気がしてきた
index.page.tsx
import React, { Suspense } from 'react'
const createP5Component = (serverSide: boolean) =>
serverSide && React.lazy(() => import('./p5'))
export function Page() {
const P5 = createP5Component(typeof window !== `undefined`)
return <Suspense fallback={<div>Loading...</div>}>{P5 && <P5 />}</Suspense>
}
metaタグをカスタマイズしてOGPが上手く出るようにする
- vite-plugin-ssr/_default.page.server.tsx at main · brillout/vite-plugin-ssrにしっかりとヒントが書いてある
- ざっくりいうと
*.page.tsx
でexport
すれば、_default.page.server.tsx
でprops的に受け取ることができるので、それを利用する - Twitterでしっかり表示したい系のheadはこんな感じ。
_default.page.server.tsx
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/mylogo.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="${desc}" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@thetalemon">
<meta name="twitter:creator" content="@thetalemon">
<meta name="twitter:description" content="${desc}" />
<meta name="twitter:title" content="${title}" />
<meta name="twitter:image" content="${img}" />
<meta property="og:image" content="${img}" />
<meta property="og:title" content="${title}" />
<meta property="og:description" content="${desc}" />
<meta property="og:url" content="${url}">
<title>${title}</title>
</head>
memo: TwitterのOGPが更新されない場合
- SNS側にOGPがキャッシュされるらしいので、キャッシュの更新作業が必要らしい
- Card Validator | Twitter Developersを使えば良いのだが プレビューは表示されないので注意。
- プレビューが失敗しても、下に
INFO: twitter:card = summary tag found
が表示されてれば、OGPの更新自体は成功しているので、Twitterに戻ってリロードして再度投稿を試みてOK
おわり
- Next.jsはSSGするのすごいカンタンだったので、Next.jsのありがたみを改めて感じた
- Vue.js / Nuxt.jsの
<client-only>
が何度も検索にひっかかっていいなあ…ってしてた - Adventerに先に投稿してわいわい!ってしてたら、TwitterのOGPが全く表示されなくて泣いたのでTwitterもデフォルトで多少はいいのを表示してくれたらいいのになーと思った。その一方で、世の中でTwitterに共有されるようなサイトは、みんなしっかりOGP設定してるんだな、と実感した。
- Vite、ビルドがはやくてVercelのデプロイも高速なのはとても体験として良いけど、困った時に情報を上手く探せないので、もっと情報増えろ〜〜と思う。この記事がその一片となればいいなってことで、投稿。
Discussion