Next.jsのAPI Routeでbcryptライブラリをインポートしてパスワードのハッシュ化を行っている。ローカルでは正常に動作するが、Vercelにデプロイすると500 FUNCTION_INVOCATION_FAILEDエラーが発生する。この原因として最も適切なものはどれか。
解説
bcryptはパスワードハッシュ化ライブラリとして広く使われていますが、内部でC++のネイティブアドオンをnode-gypでコンパイルして利用します。ローカル環境ではOSに合わせたビルドツールチェーンが揃っているため問題なく動作しますが、Vercelのサーバーレス関数の実行環境ではネイティブバイナリの互換性が保証されず、インポート時点でクラッシュして500 FUNCTION_INVOCATION_FAILEDが返ります。npmパッケージのインポート自体は問題ありません。API Routeでasync/awaitは普通に使えます。メモリ上限もデフォルト1024MB(1GB)であり、64MBということはありません。ネイティブ依存とピュアJS実装の違いNode.jsのパッケージには、JavaScriptだけで書かれた「ピュアJS」パッケージと、C/C++で書かれたコードをビルドして使う「ネイティブ依存」パッケージがあります。ネイティブ依存パッケージはOS・アーキテクチャごとにビルド結果が異なるため、ローカルのmacOSでビルドしたバイナリがVercelのLinux環境で動かない、という問題が起きます。bcryptの代わりにbcryptjs(ピュアJavaScript実装)を使えば、この問題は解消します。// bcrypt(ネイティブ依存)の代わりに // bcryptjs(ピュアJS)を使う import bcrypt from 'bcryptjs'; const hash = await bcrypt.hash(password, 10); const isMatch = await bcrypt.compare(password, hash);同様の問題が起きやすいパッケージsharp: 画像処理ライブラリ。ただしNext.jsの画像最適化にはVercel側で対応済みのため、API Routeで直接使う場合のみ注意が必要canvas: node-canvasもネイティブ依存。サーバーレス環境ではLambda用のレイヤーが必要になるケースがあるsqlite3: ネイティブバイナリを含む。サーバーレス環境ではbetter-sqlite3やPlanetScale等の外部DBサービスが推奨されるデプロイ前にnpm lsで依存ツリーを確認し、ネイティブ依存がないかチェックする習慣をつけると、この種のトラブルを未然に防げます。