@vercel/og を試す
Next.js v13 のリリースと一緒に og 作成できるライブラリが発表されているので試してみる
インストール
npm i @vercel/og
サンプルコード
pages/api/og.tsx
import { ImageResponse } from '@vercel/og';
export const config = {
runtime: 'experimental-edge',
};
export default function () {
return new ImageResponse(
(
<div
style={{
fontSize: 128,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center',
}}
>
Hello world!
</div>
),
{
width: 1200,
height: 600,
},
);
}
こんな見た目の画像ができた。
Dynamic title
クエリストリングで文字列を渡して動的に表示する内容を変更できる。
import { ImageResponse } from '@vercel/og';
import { NextRequest } from 'next/server';
export const config = {
runtime: 'experimental-edge',
};
export default function handler(req: NextRequest) {
try {
const { searchParams } = new URL(req.url);
const title = searchParams.has('title')
? searchParams.get('title')?.slice(0, 100)
: 'Default';
return new ImageResponse(
(
<div
style={{
fontSize: 50,
background: '#191919',
color: '#f4f4f5',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{title}
</div>
),
{
width: 1200,
height: 600,
}
);
} catch (e: any) {
console.log(`${e.message}`);
return new Response(`Failed to generate the image`, {
status: 500,
});
}
}
http://localhost:3000/api/og?title=kimromi
Custom font
https://vercel.com/docs/concepts/functions/edge-functions/og-image-examples#using-a-custom-font
Google Fonts とかからダウンロードしたフォントを利用できる。
import { ImageResponse } from '@vercel/og';
import { NextRequest } from 'next/server';
export const config = {
runtime: 'experimental-edge',
};
const font = fetch(
new URL('../../assets/NotoSansJP-Medium.otf', import.meta.url)
).then((res) => res.arrayBuffer());
export default async function handler(req: NextRequest) {
try {
const { searchParams } = new URL(req.url);
const fontData = await font;
const title = searchParams.has('title')
? searchParams.get('title')?.slice(0, 100)
: 'kimromi';
return new ImageResponse(
(
<div
style={{
background: '#191919',
color: '#f4f4f5',
display: 'flex',
width: '100%',
height: '100%',
}}
>
<div
style={{
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
padding: '100px 150px 0 150px',
wordBreak: 'break-all',
fontSize: 60,
fontFamily: '"NotoSansJP"',
}}
>
{title}
</div>
<div
style={{
position: 'absolute',
right: 120,
bottom: 80,
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
fontSize: 32,
fontFamily: 'serif',
}}
>
<img
width="32"
height="32"
src="https://kimromi.com/logo.png"
style={{
marginRight: '0.75rem',
}}
/>
kimromi
</div>
</div>
),
{
width: 1200,
height: 630,
fonts: [
{
name: 'NotoSansJP',
data: fontData,
style: 'normal',
},
],
}
);
} catch (e: any) {
console.log(`${e.message}`);
return new Response(`Failed to generate the image`, {
status: 500,
});
}
}
http://localhost:3000/api/og?title=ポートフォリオサイトを作った
フォントファイルのサイズを小さくする
Edge Function のサイズ制限が 1.02MB なのでフォントファイルが大きいとデプロイに失敗した。
以下のサイトを参考にサブセット化し必要な文字列だけ含んだフォントファイルにして 4.6MB → 415KB にした。
https://github.com/kimromi/kimromi.com/pull/40 で試してみて kimromi.com に導入完了。