🔥
Next.js + Vercel で OGP の画像を動的に生成する
はじめに
OGP を node-canvas
で画像を生成し、返却する API を Next.js で実装しました
/pages/api/ogp.ts
import { createCanvas } from 'canvas';
export default async (req, res) => {
const canvas = createCanvas(1200, 630);
const ctx = canvas.getContext('2d');
ctx.font = '20px';
ctx.fillText('hoge', 60, 120);
const buf = canvas.toBuffer();
const cacheAge = 7 * 24 * 60;
res.setHeader('Content-Type', 'image/png');
res.setHeader('Content-Length', buf.length);
res.setHeader('Cache-Control', `public, max-age=${cacheAge}`);
res.setHeader('Expires', new Date(Date.now() + cacheAge).toUTCString());
res.status(200).end(buf);
};
この API を Vercel で動かすのに一苦労したので、まとめていきます
libuuid.so.1 エラー
まず libuuid.so.1
エラーが発生しました
Error: libuuid.so.1: cannot open shared object file: No such file or directory
解消するためには下記 Issue を参考に
このようなビルドするスクリプトを書けば解消されます
{
"scripts": {
"build": "next build",
"now-build": "yum install libuuid-devel libmount-devel && cp /lib64/{libuuid,libmount,libblkid}.so.1 node_modules/canvas/build/Release/ && npm run build"
}
/lib64/libz.so.1 エラー
libuuid.so.1
エラーは出なくなったのですが、次は /lib64/libz.so.1
エラーが出るようになりました
Error: /lib64/libz.so.1: version `ZLIB_1.2.9' not found (required by /var/task/node_modules/canvas/build/Release/libpng16.so.16)
解消するために下記 Issue を参考に
node-canvas
のバージョンを 2.6.1
にすることで解消されます
{
"dependencies": {
"canvas": "2.6.1",
}
}
Error: Package: glibc-2.26-48.amzn2.i686 (amzn2-core) エラー
2021.09.19 にリリースをしていた際に新たにエラーが出るようになり、Vercel のデプロイ処理が中断されるようになりました。
16:25:27.161 Error: Package: glibc-2.26-48.amzn2.i686 (amzn2-core)
16:25:27.161 Requires: glibc-common = 2.26-48.amzn2
16:25:27.161 Installed: glibc-common-2.26-53.amzn2.x86_64 (@amzn2-core)
16:25:27.164 glibc-common = 2.26-48.amzn2
16:25:27.164 You could try using --skip-broken to work around the problem
16:25:27.355 You could try running: rpm -Va --nofiles --nodigest
16:25:27.395 error Command failed with exit code 1.
16:25:27.395 info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
16:25:27.418 Error: Command "yarn run now-build" exited with 1
上記ログが出ていたので、 --skip-broken
をしてすることで回避しました。
{
"scripts": {
"build": "next build",
"now-build": "yum install libuuid-devel libmount-devel --skip-broken && cp /lib64/{libuuid,libmount,libblkid}.so.1 node_modules/canvas/build/Release/ && npm run build"
}
文字化け
これでやっと動くようになったのですが、日本語が文字化けします
対応としては registerFont
を利用してフォントファイルを読み込みます
/pages/api/ogp.ts
import { createCanvas, registerFont } from 'canvas';
import * as path from 'path';
export default async (req, res) => {
const canvas = createCanvas(1200, 630);
const ctx = canvas.getContext('2d');
registerFont(path.resolve('./fonts/NotoSansJP-Regular.otf'), {
family: 'Noto',
});
ctx.font = '20px "Noto"';
ctx.fillText('あいうえお', 60, 120);
const buf = canvas.toBuffer();
const cacheAge = 7 * 24 * 60;
res.setHeader('Content-Type', 'image/png');
res.setHeader('Content-Length', buf.length);
res.setHeader('Cache-Control', `public, max-age=${cacheAge}`);
res.setHeader('Expires', new Date(Date.now() + cacheAge).toUTCString());
res.status(200).end(buf);
};
ディレクトリは下記構成になっています
- fonts
- NotoSansJP-Regular.otf
- pages
- api
- ogp.ts
- api
下記では public
ディレクトリに置いたフォントファイルが読み込めないと書かれていましたが、fonts
ディレクトリに置いたからか自分の環境では読み込むことが出来ました
さいごに
これで無事 OGP を動的に生成することができました!
Discussion