edit_calendar   event_repeat  

Nuxt3 + VercelでOGイメージを動的に生成する

概要

この記事ではNuxt3とVercelを使用してOGイメージを動的に生成する。Nuxt3で新たに追加されたserver機能とSatoriというライブラリを使うことで簡単にOGイメージを動的に生成できる。

はじめに

ブログを作ろうと思い、ある程度完成したので初投稿してみる。SNS等でURLを投稿した際にSEOを意識してOG系のmeta情報を動的に反映させたいと思い、titleやdescriptionは簡単に設定できたが、画像をどうすればいいか悩んでいた。するとVercelがNext.js向けにvercel/ogというライブラリを開発していたので、これを参考に実装できないか検討してみた。

関連ライブラリのインストール

Satoriのインストール

vercel/ogは内部的にsatoriというライブラリを利用しているのでインストールする。satoriはJSXやReact LikeなobjectからSVGを生成するライブラリ。
$ yarn add satori
vercel/og及びsatoriはOGイメージを動的に生成するAPIのエンドポイントをjsxで簡単に作成することができるが、今回はNuxt.jsのためjsファイルで作成する。(jsxでもできるのかは不明)

Resvgのインストール

svgをpng形式に変換するためResvgをインストールする。
$ yarn add @resvg/resvg-js

APIのエンドポイント作成

/server/api にog.tsファイルを作成する。内部的な実装は別ファイルに切り出すことで、コードの見通しが良くなり、ここでは画像が生成されるんだろうと予想がつく。
import { generateImage } from '~/lib/generateImg'
export default defineEventHandler(async (event) => {   const query = getQuery(event)   const { title, fontFamily } = query   const ogImage = await generateImage({ title, fontFamily })   return ogImage })

generateImage.ts
import satori, { SatoriOptions } from 'satori'
import { Resvg } from '@resvg/resvg-js' import { loadGoogleFont } from '../loadGoogleFont' import { Props } from './type' const BASE_FONT_FAMILY = 'M PLUS Rounded 1c' const PLOT_WIDTH = 1200 const PLOT_HEIGHT = 630 export const generateImage = async ({   title,   fontFamily, }: Props): Promise<Buffer> => {   const fontData = await loadGoogleFont({     family: fontFamily ?? BASE_FONT_FAMILY,   })   const element = //ここにReactLikeなオブジェクトを書く   const options: SatoriOptions = {     width: PLOT_WIDTH,     height: PLOT_HEIGHT,     fonts: [       {         name: fontFamily ?? BASE_FONT_FAMILY,         data: fontData,         weight: 400,         style: 'normal',       },     ],   }   const svg = await satori(element, options)   const resvg = new Resvg(svg)   const pngData = resvg.render()   const pngBuffer = pngData.asPng()   return pngBuffer }

loadGoogleFontは引数で渡されたfont-familyがあればそのfontを、なければBASE_FONTをgoogle fontから読み込んでいる。
このあたりは、Cloudflare Workers で画像生成の記事とhttps://github.com/kvnang/workers-og/blob/main/packages/workers-og/src/font.tsの実装を参考にしている。

Vercelへデプロイする設定

vercelでserver/apiを有効にするためにnuxt.config.tsへ以下の設定を追記する。
nitro: {
  preset; 'vercel',
}
あとは各ページに設定してVercelにデプロイして確認するだけ。

Vercelのデプロイ設定

vercelの設定を以下のようにOverrideする。

meta関連タグの設定

あとは[id].vue等の動的に変化させたいページに上記で設定したエンドポイントを設定する。
ついでに他のmetaタグも設定しておく。
<template>
  <Title>{{ article.title }}</Title>
  <Meta name="description" :content="article.description" />
  <Meta property="og:title" :content="article.title" />
  <Meta property="og:url" :content="config.baseUrl + route.path" />
  <Meta property="og:image" :content="`${config.baseUrl}/api/og?title=${encodeURI(article.title)}`" />
  <Meta property="og:description" :content="article.description" />
</template>

OGイメージの確認

queryでtitleを指定しない場合はデフォルトのメッセージを表示するようにしている。 

/api/og

/api/og?title=Hello World 

参考

vercel/satori
yisibl/resvg-js
Cloudflare Workers で画像生成
©2022 - Spogineer