VercelのServerless Functionでplaywright-coreが動作しない現象
問題の概要
VercelにデプロイしたNext.js製サイトにおいて、OGP画像を生成するためAPI Routes(Serverless Function)を利用している。
具体的には上の記事と同様に、playwright-coreとplaywright-aws-lambdaを利用してスクリーンショットを撮影しているが、なぜかplaywright-coreをv1.19.2以上に更新すると動作しない現象が起きた。厳密に言うと、ローカルの開発サーバでは動作し、なおかつデプロイも成功するが、デプロイ後にアクセスを行うとエラーが発生する。
解決策(追記)
Next.jsをv12.1.5に更新することで解消した。(依存パッケージの@vercel/nft
がv0.18.1に更新されるため)
環境
おそらく関連がありそうなもの
- Next.js v12.1.4
- pnpm v6.32.6
- playwright-core v>=1.19.2
- @vercel/nft v1.18.0
エラー内容
エラーの内容は以下(ツイート画面で申し訳ない)。
見た感じ、playwright-core
以下のlib/utils/comparators.js
でモジュール解決のエラーが起きているようだ。これはコンパイル前のsrc/utils/comparators.ts
にあたり、該当箇所はこんな感じ:
// Note: we require the pngjs version of pixelmatch to avoid version mismatches.
const { PNG } = require(require.resolve('pngjs', { paths: [require.resolve('pixelmatch')] })) as typeof import('pngjs');
playwright-core
の変更履歴を見ると、v1.19.1とv1.19.2の間でこのコードを含むファイルが付加されており、ここがエラーの原因箇所であることは間違いなさそうだ。
他方、同じ構成でもすべての環境でエラーが起きているわけではない。例えば以下のアプリはplaywright-core
の最新バージョンをVercel上で使用しているが、特に問題がある様子はない。
さらにv1.19.2のリリースから1ヶ月以上経っているにもかかわらず、playwright-core
のリポジトリには特段Issueが立っていない。
とすると問題はこちらの環境にありそうだ。ここでパッケージマネージャにpnpmを使っていることに思い当たり、これが原因だと睨んだ。
最初に試したのはpnpmの--shamefully-hoist
オプションだ。pnpmが生成するnode_modules
の構造はnpm、yarnとは異なるが、このオプションではpnpmに他と同様のnode_modulesを生成させる。Vercel上のインストールコマンドにこれを用いれば、他のパッケージマネージャと同様の形でファイルがデプロイされるのではないか? というわけだ。だがこれも効果はなかった。
次に、Vercelで使用するパッケージマネージャを強引にnpm / yarnに切り替えてみた。ところが今度はlockfileがないせいか、ビルド時点でエラーが出てあえなく断念した。むべなるかな。
エラー元のコードに立ち返ってみる。該当箇所はpngjs
をrequireする際にpixelmatch
の内部から引っ張っているらしい。おそらくはこのpngjsが存在しなくてコケているのだろう。
このへんで頭を冷やし、Vercelのデプロイ時の挙動に思いを馳せてみる。Vercel上のServerless Functionは、ビルド時に依存関係をトレースされてから必要なもののみがデプロイされるようになっている(らしい)。この過程はビルドログにも(ちょっとだけ)残っている。
ではVercelはどのようにコードをトレースしているのか? 調べた感じ、@vercel/nftが使われているようだ。ローカルで問題なく動作していたということは、このトレースの過程で必要なコードを把握しきれておらず、それによってデプロイ後にエラーを吐いた可能性がある。
そこで@vercel/nft
のリポジトリを漁ると、以下のようなPull Requestを発見した。
Adds unit and integration tests for the pixelmatch package which requires a special case for including the bin directory to correctly trace the dependency pngjs
Fixes a playwright bug https://github.com/microsoft/playwright/blob/7f513360681d2517caa24d266def9b3a7be4f469/packages/playwright-core/src/utils/comparators.ts#L23-L24
どうやら当たりのようだ。しかもマージされたのが(執筆時点より)20時間前! 直後に新しいリリース(v0.18.1)も出ており、これが反映されればエラーが解決するかもしれない。
@vercel/nft
に依存しているライブラリの中に、@serverless-stack/nextjs-lambdaがある。名前からしてこれがNext.jsのLambda環境に使われていそうだが(完全に勘)、こちらは現時点ではまだ上流の更新を反映していない。というわけで、一旦このパッケージの更新を待ってみる。
↑は嘘で、普通にNext.js本体に@vercel/nft
が使われていた。ちょうど下のプルリクでv0.18.1がマージされ、Next.js v12.1.5に取り込まれていたので、試してみる。
動いた!原因は@vercel/nft
にあったようだ。