概要
Next.jsのアプリをCloud Runにデプロイしようとしたところ、npm run devでは問題なく動作するのに、npm run build(デプロイ時のビルド)でのみエラーが発生しました。
エラーの内容は「環境変数が存在しない」というもので、SupabaseのURLやキーはすでに設定済みにも関わらずbuildではなぜかうまくいかないというものでした。
原因
原因はbuildフェーズで実行されるコードの中でSupabaseを初期化していたことでした。
ここで重要になる前提がbuild と runtime は別のフェーズだという点です。
この辺りの認識が浅かったので少し調べてみることにしました。
Next.js内部の実行フェーズ
Next.js には大きく分けて次の 2 つの実行フェーズがあります。
runtime(実行時)
- ユーザーがページにアクセスしたときに実行される
- Server Component / API Route / Server Action がリクエストごとに動く
- 環境変数や外部サービス(DB / API)が利用できる前提
一般的に「サーバーでコードが動く」と言うとき、多くの場合はこの runtime を指しています。
build
-
npm run buildやnext buildが実行されるタイミング - デプロイ前に静的生成のため
page.tsxが評価・実行される - 実行環境や環境変数は runtime と一致しないことがある
Next.js(App Router)は、静的に生成できるページについては build 時にコードを実行する ため、このフェーズで runtime 前提の処理を書くとビルドエラーになります。
- runtime:ユーザーアクセス時に実行される
- build:デプロイ前にページを事前生成するために実行される
「Next.js は SSR アプリでも build 時にコードを一度実行することがある」
という前提を置いていなかった
ReactとNext.jsのbuild実行時の違い
今回選んだ対応
今回は静的生成を使う設計を維持したかったため、buildフェーズにもSupabaseの環境変数を渡す対応を取りました。
Cloud Runのデプロイ時にruntime用だけでなくbuild用にも環境変数を設定します。
gcloud run deploy rootlink-server-v2 \
--source . \
--region asia-northeast1 \
--allow-unauthenticated \
--set-build-env-vars NEXT_PUBLIC_SUPABASE_URL=xxx,NEXT_PUBLIC_SUPABASE_ANON_KEY=yyy \
--set-env-vars NEXT_PUBLIC_SUPABASE_URL=xxx,NEXT_PUBLIC_SUPABASE_ANON_KEY=yyy
またこのコマンドは長いので、私は一連のものをビルド用のシェルスクリプトにまとめました。
これにより
- buildフェーズ
- runtimeフェーズ
の両方でSupabaseが初期化できるようになり、ビルドエラーは解消しました。
まとめ
- Next.jsではbuildフェーズでもコードが実行される
- 今回はbuildでもSupabaseを使う前提に切り替えることで解決した
- buildとruntimeの違いを意識すると同様のエラーは整理して対処できる
多分他にもソリューションはたくさんあると思いますが、個人開発で最低限のセキュリティを担保したい人には多少参考になるのかなと思いました。
