iOS&Androidスマートフォン開発(Swift/Kotlin/React-Native) および Next.js/LaravelをはじめとしたWeb開発ならば、ぜひ創業13年の弊社にお任せください。ワンストップでお届けします。お問合せはこちらから

node-canvasがVercelのビルドで「pixman-1 not found」になる。Node 24で詰んだときの逃げ道

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

yuku_tasのアイコン

こんにちは、Webサービス開発者のyuku_tasです。

簡単なプロフィール: MoldSpoon Inc.代表。開業から15年、業界に携わって20年。Webサイト/iOS/Androidアプリ開発から、データ分析業務・コンサル業務、ベンチャーから保険会社まで様々な案件を個人会社の形で請け負ってまいりました。詳しくはこちら

はじめに

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)**を配布しているからです。インストール時にダウンロードして置くだけなので、一瞬で終わります。

問題は、ここが外れたときです。

  1. インストール時、自分の環境に合うビルド済みバイナリを探す
  2. 見つからないと、ソースからのビルドにフォールバックする
  3. ソースビルドにはcairo・pixmanなどのシステムライブラリが必要
  4. Vercelのビルドイメージにそれらは入っていない
  5. pixman-1 not foundで失敗

つまりエラーメッセージはpixmanを指していますが、本当の原因は「ビルド済みバイナリが見つからなかったこと」です。pixmanを入れようとする方向に進むと、Vercel上ではまず行き止まりになります。

なぜ急に見つからなくなったのか

ビルド済みバイナリはNodeのバージョンごとに用意されています。正確には、Nodeのメジャーバージョンに対応する**ABIバージョン(NODE_MODULE_VERSION)**ごとです。

  • Node 22 → ABI 127
  • Node 24 → ABI 137

node-canvas 2.x は、Node 24(ABI 137)向けのビルド済みバイナリを配布していません。 そのため24へ上げた瞬間に「見つからない」側へ落ち、ソースビルドが始まり、そして失敗します。

Node 18や20で動いていたものが、バージョンを上げただけで壊れる理由はここにあります。コードは1行も変えていないのに落ちます。

ローカルでは再現しないことがある

紛らわしいのは、macOSのローカルでは通ってしまう場合があることです。Homebrewでcairoやpixmanを入れていれば、ソースビルドが成功してしまうからです。

「手元では動くのにVercelで落ちる」となったら、システムライブラリの有無を疑ってください。Vercelのビルドイメージには画像処理系のシステムライブラリは基本的に入っていません。

逃げ道1: そもそも使っているか確認する

先にこれをやってください。うちの結末はこれでした。

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に依存していれば消せませんが、うちは依存元が存在しない残骸でした。おそらく昔なにかを試した名残です。

依存を消して、ビルドは通るようになりました。

逃げ道2: サーバー側の画像生成は@vercel/ogにする

実際に使っている場合の代替です。OGP画像の動的生成が目的なら、**@vercel/og**が有力です。

  • ネイティブ依存がありません(satoriベース。内部はWASM)
  • Vercel上での動作が前提に作られている
  • JSXでレイアウトを書ける
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バージョン向けのバイナリが実際に配布されているか必ず確認してください。 今回踏んだ穴と同じものが待っています。

逃げ道3: ブラウザ側で描く

そもそもサーバーで描く必要があるのか、という話もあります。

うちのビジネスモデルキャンバスは、画面のスクリーンショットをhtml2canvasで撮って保存しています。ブラウザ側で完結するので、ビルド環境のシステムライブラリとは無縁です。

「ユーザーが見ている画面をそのまま画像にしたい」なら、こちらのほうが素直で、見た目のズレも起きません。

保存先の設計については別記事にしました。

よくある質問(FAQ)

Q. Vercelのビルドイメージにcairoを入れることはできますか?

installCommandでパッケージマネージャを叩く手はありますが、おすすめしません。 ビルドのたびにシステムライブラリを入れることになり、時間もかかれば、ビルドイメージが更新されたときに壊れます。

「動く構成」ではなく「壊れやすい構成」を作ることになります。ネイティブ依存を外す方向に進んだほうが結局は安上がりです。

Q. Nodeのバージョンを下げれば直りますか?

直りますが、VercelはEOLを迎えたNodeでの新規ビルドを打ち切ります。 一時しのぎにしかならず、期限も自分で決められません。

私は「node-canvasを残すためにNodeを古いままにする」という取引は割に合わないと判断しました。

Q. ビルドログのどこを見れば犯人が分かりますか?

node-gypが動き始めた行を探してください。その直前に出ているパッケージ名が犯人です。ソースビルドに落ちているパッケージは、ログにコンパイルの進捗が延々と出るのですぐ分かります。

インストールが妙に長い場合も同じサインです。ビルド済みバイナリで済んでいるなら一瞬で終わります。

Q. package-lock.jsonyarn.lockが両方あります

それも直してください。 うちも両方あって、package-lock.jsonのほうはcanvasすら含まない乖離した状態でした。ビルドログでも混在が警告されていました。

どちらか一方に決めて、もう片方は消すのが正解です。この話は依存の棚卸しの記事に書きました。

まとめ

  • pixman-1 not foundは、ビルド済みバイナリが見つからずソースビルドに落ちた結果
  • node-canvas 2.xにはNode 24(ABI 137)向けのバイナリが無い
  • Vercelのビルドイメージにcairo・pixmanは入っていない(入れる方向に進まない)
  • まず本当に使っているかimportで検索する。うちは使っていなかった
  • OGP画像なら**@vercel/og、画面の画像化ならhtml2canvas**で足りることが多い

「Nodeを上げたら、触ってもいないパッケージのせいでビルドが落ちた」というのは、ネイティブ依存を抱えているときの典型的な壊れ方です。使っていない依存ほど、こういう形で牙を剥きます。


この記事が何かのお役に立てれば幸いです。
最後までお読みいただきありがとうございました!

Share Me!