2026年09月06日 10:20 / - PV

Node.jsのバージョンを24へ上げたところ、Vercelのビルドがこんなエラーで落ちるようになりました。
Package 'pixman-1', required by 'virtual:world', not found
あるいは、node-gypのログの中にこう出ます。
Package pixman-1 was not found in the pkg-config search path.
No package 'pixman-1' found
犯人はnode-canvas(npm上のcanvasパッケージ)でした。しかも最終的な結末は「そのパッケージ、うちでは1行も使っていなかった」です。同じ落とし方をする人はそこそこいると思うので、原因と逃げ道を残しておきます。
node-canvasはネイティブモジュールです。C++で書かれた部分をビルドして使います。
普段この工程が見えないのは、node-canvasが主要な環境向けに**ビルド済みバイナリ(prebuilt binary)**を配布しているからです。インストール時にダウンロードして置くだけなので、一瞬で終わります。
問題は、ここが外れたときです。
pixman-1 not foundで失敗つまりエラーメッセージはpixmanを指していますが、本当の原因は「ビルド済みバイナリが見つからなかったこと」です。pixmanを入れようとする方向に進むと、Vercel上ではまず行き止まりになります。
ビルド済みバイナリはNodeのバージョンごとに用意されています。正確には、Nodeのメジャーバージョンに対応する**ABIバージョン(NODE_MODULE_VERSION)**ごとです。
node-canvas 2.x は、Node 24(ABI 137)向けのビルド済みバイナリを配布していません。 そのため24へ上げた瞬間に「見つからない」側へ落ち、ソースビルドが始まり、そして失敗します。
Node 18や20で動いていたものが、バージョンを上げただけで壊れる理由はここにあります。コードは1行も変えていないのに落ちます。
紛らわしいのは、macOSのローカルでは通ってしまう場合があることです。Homebrewでcairoやpixmanを入れていれば、ソースビルドが成功してしまうからです。
「手元では動くのにVercelで落ちる」となったら、システムライブラリの有無を疑ってください。Vercelのビルドイメージには画像処理系のシステムライブラリは基本的に入っていません。
先にこれをやってください。うちの結末はこれでした。
grep -rn "from 'canvas'\|require('canvas')" --include=*.ts --include=*.tsx --include=*.js --include=*.jsx .
1件も出ませんでした。
紛らわしかったのは、canvasという単語だけならプロジェクト中にいくらでもあったことです。
BusinessModelCanvas … 自作コンポーネントの名前canvasType … 自前の型html2canvas … 別のパッケージ(ブラウザ側で動く。node-canvasとは無関係)<canvas> … HTML要素「canvasで検索したら山ほど出たので使っているはず」と判断すると間違えます。importの形で検索してください。
package.jsonから消したあと、yarn.lock側も確認しました。他のパッケージがnode-canvasに依存していれば消せませんが、うちは依存元が存在しない残骸でした。おそらく昔なにかを試した名残です。
依存を消して、ビルドは通るようになりました。
@vercel/ogにする実際に使っている場合の代替です。OGP画像の動的生成が目的なら、**@vercel/og**が有力です。
import { ImageResponse } from '@vercel/og'
export const config = { runtime: 'edge' }
export default function handler() {
return new ImageResponse(
(
<div style={{ display: 'flex', fontSize: 64, background: '#fff', width: '100%', height: '100%', alignItems: 'center', justifyContent: 'center' }}>
こんにちは
</div>
),
{ width: 1200, height: 630 },
)
}
制約もあります。CSSは一部しかサポートされていませんし、<canvas>のようにピクセル単位で描くAPIではありません。「テキストと画像を組み合わせたカードを作る」用途なら十分ですが、画像処理そのもの(フィルタ、合成、変形)をしたい場合は用途が違います。
その場合は、ビルド済みバイナリを配布している別実装(@napi-rs/canvasなど)を検討することになります。ただし採用前に、使いたいNodeバージョン向けのバイナリが実際に配布されているか必ず確認してください。 今回踏んだ穴と同じものが待っています。
そもそもサーバーで描く必要があるのか、という話もあります。
うちのビジネスモデルキャンバスは、画面のスクリーンショットをhtml2canvasで撮って保存しています。ブラウザ側で完結するので、ビルド環境のシステムライブラリとは無縁です。
「ユーザーが見ている画面をそのまま画像にしたい」なら、こちらのほうが素直で、見た目のズレも起きません。
保存先の設計については別記事にしました。
installCommandでパッケージマネージャを叩く手はありますが、おすすめしません。 ビルドのたびにシステムライブラリを入れることになり、時間もかかれば、ビルドイメージが更新されたときに壊れます。
「動く構成」ではなく「壊れやすい構成」を作ることになります。ネイティブ依存を外す方向に進んだほうが結局は安上がりです。
直りますが、VercelはEOLを迎えたNodeでの新規ビルドを打ち切ります。 一時しのぎにしかならず、期限も自分で決められません。
私は「node-canvasを残すためにNodeを古いままにする」という取引は割に合わないと判断しました。
node-gypが動き始めた行を探してください。その直前に出ているパッケージ名が犯人です。ソースビルドに落ちているパッケージは、ログにコンパイルの進捗が延々と出るのですぐ分かります。
インストールが妙に長い場合も同じサインです。ビルド済みバイナリで済んでいるなら一瞬で終わります。
package-lock.jsonとyarn.lockが両方ありますそれも直してください。 うちも両方あって、package-lock.jsonのほうはcanvasすら含まない乖離した状態でした。ビルドログでも混在が警告されていました。
どちらか一方に決めて、もう片方は消すのが正解です。この話は依存の棚卸しの記事に書きました。
pixman-1 not foundは、ビルド済みバイナリが見つからずソースビルドに落ちた結果@vercel/og、画面の画像化ならhtml2canvas**で足りることが多い「Nodeを上げたら、触ってもいないパッケージのせいでビルドが落ちた」というのは、ネイティブ依存を抱えているときの典型的な壊れ方です。使っていない依存ほど、こういう形で牙を剥きます。
この記事が何かのお役に立てれば幸いです。
最後までお読みいただきありがとうございました!
Share Me!