😄

Next.jsのSSGでogp画像を生成し設定する

2024/09/13に公開

Next.jsのSSGでogp画像を生成し設定する

next/ogを使用せずにogp画像を設定できるか興味本位でやってみた。ogp画像確認サイトで確認したらちゃんと表示されてた。Xの投稿フォームにURL貼ってもカードで表示されてた

成果物

コード

ビルド時にcanavsを使って画像を生成し、ogp.pngとしてpublicフォルダに保存する。その写真のURLをpropsとして渡してmetaタグに設定する。

import { createCanvas } from "@napi-rs/canvas";
import { writeFileSync } from "fs";
import Head from "next/head";
import Image from "next/image";
import path from "path";
import { cwd } from "process";

interface Props {
  url: string;
  imgUrl: string;
  file: string;
}

const Home = ({ url, imgUrl, file }: Props) => {
  return (
    <>
      <Head>
        <title>OGPの生成の練習</title>
        <meta charSet="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta name="robots" content="noindex, nofollow" />

        <meta name="description" content={"OGPの生成の練習"} />

        <meta property="og:title" content={"OGPの生成の練習"} />

        <meta name="og:description" content={"description"} />

        <meta property="og:type" content={"website"} />
        <meta property="og:url" content={url} />
        <meta property="og:site_name" content={"OGPの生成の練習"} />
        <meta property="og:image" content={imgUrl} />

        <meta name="twitter:title" content={"OGPの生成の練習"} />
        <meta name="twitter:description" content={"OGPの生成の練習"} />
        <meta name="twitter:image" content={imgUrl} />

        <link
          rel="canonical"
          href={url}
        />
      </Head>
      <div>
        <Image 
          src={file}
          alt="画像"
          width={1200}
          height={630}
          />
      </div>
    </>
  );
}

export const getStaticProps = async () => {
  const width = 1200;
  const height = 630;

  const canvas = createCanvas(width, height);
  const ctx = canvas.getContext("2d");

  ctx.font = 'bold 64px';
  ctx.fillStyle = '#1F2937';
  ctx.textBaseline = 'top';
  ctx.textAlign = 'center';

  ctx.fillText("Hello World", 500, 100);
  const url = canvas.toDataURL("image/png");
  const image = url.split(";base64,").pop();

  if(!image) return;
  
  writeFileSync(path.join(cwd(), "public", 'ogp.png'), image, {
    encoding: "base64"
  });

  return {
    props: {
      url: process.env.BASE_URL,
      imgUrl: 'URL/ogp.png', // ogp画像用の写真のURL
      file: '/ogp.png' // publicフォルダに保存した写真にアクセスする場合
    }
  }
}

export default Home;

base64エンコードの文字列をそのまま渡してもogp画像は設定される。これは指定してもよいものなのかわからん

  if(!image) return;
  
  writeFileSync(path.join(cwd(), "public", 'ogp.png'), image, {
    encoding: "base64"
  });

  return {
    props: {
      url: process.env.BASE_URL,
      imgUrl: 'https://generate-ogp-images-with-ssg.vercel.app/ogp.png',
      file: '/ogp.png',
      base64URL: url,
    }
  }

最後に

間違っていること、もっといい方法があればコメントに書いていただけると幸いです。
よろしくお願いいたします。

GitHubで編集を提案

Discussion