🔥

Next.js + Vercel で OGP の画像を動的に生成する

2021/06/15に公開

はじめに

OGP を node-canvas で画像を生成し、返却する API を Next.js で実装しました

https://www.npmjs.com/package/canvas

/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 を参考に

https://github.com/vercel/vercel/issues/3460#issuecomment-583072848

このようなビルドするスクリプトを書けば解消されます

{
  "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 を参考に

https://github.com/Automattic/node-canvas/issues/1779#issuecomment-819827079

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

下記では public ディレクトリに置いたフォントファイルが読み込めないと書かれていましたが、fonts ディレクトリに置いたからか自分の環境では読み込むことが出来ました

https://qiita.com/uhyo/items/d9c5e78fcbc233bd5b17#フォントが読み込めない

さいごに

これで無事 OGP を動的に生成することができました!

https://enjoy-sfv-more.com/api/combos/ogp?comboId=1i8jsQveq34JYHJzCHlX

Discussion