Firebase Hosting にデプロイ時にStaging用またはProduction用の環境変数を読み込む
投稿日: 2024/06/10
実務レベルでプロダクト開発を行おうとするとき、Production環境(本番環境)とほぼ同じ環境であるStaging環境も構築することになると思います。Production環境に変更を反映する前にStaging環境で動作確認するわけです。
FirebaseでStaging環境を作成するには、Production環境とは別のFirebaseプロジェクトとして作成します。そのときFirebase Hostingにデプロイする静的Webサイトのソースコードは共有し、処理をビルド時の環境変数で切り分けることになります。例えばViteでは、.env.staging
と.env.prouduction
のようなファイルを用意して、Staging環境にデプロイするときは.env.staging
を読み取ってビルドし、Production環境にデプロイするときは.env.roduction
を読み取ってビルドしなければなりません。
Firebase Hosting の Predeploy / Postdeploy 機能を使う方法
Firebase Hosting にはデプロイコマンドを実行したときにデプロイの前後に任意のコマンドを自動実行する Predeploy / Postdeploy 機能があるのでそれを使います。
前提としてFirebaseプロジェクトのディレクトリ構成は以下のようになっています。
. ├── Dockerfile ├── README.md ├── data ├── docker-compose.yml ├── firebase-debug.log ├── firebase.json ├── firestore-debug.log ├── firestore.indexes.json ├── firestore.rules ├── hostings └── web ├── README.md ├── astro.config.mjs ├── build_by_firebase_deploy.sh ├── dist ├── node_modules ├── package-lock.json ├── package.json ├── public ├── src ├── tsconfig.json └── vitest.config.ts ├── public ├── rules └── ui-debug.log
他の設定は以下のような感じで、Firebase Hostingのビルドファイルはhostings/web/dist
に生成されるようにしています。ファイルパスは自身の好みに従ってください。
firebase.json
{ ... "hosting": { "public": "hostings/web/dist", ... },
.firebaserc
{ "projects": { "default": "my-project-staging", "staging": "my-project-staging", "production": "my-project-production" } }
方法の説明をしていきます。
まず、ビルド用のコマンドをpackage.json
に追加します。僕はフレームワークにAstroを使っていますが、他のフレームワークでも同じ方法で問題ないです。
package.json
"scripts": { ... - "build": "astro check && astro build" + "build:base": "astro check && astro build", + "build:staging": "npm run build:base -- --mode staging", + "build:production": "npm run build:base -- --mode production" },
modeオプションをつけてそれぞれの環境ごとに異なる環境変数を読み込むようにしています。
また、間違って実行しないように念のため元のbuildコマンドは削除しています。
次にビルド Predeploy 機能で実行するデプロイコマンドを書きます。ちょっと長くなるのでシェルスクリプトファイルに書きます。
hostings/web/build_by_firebase_deploy.sh
if [ "$GCLOUD_PROJECT" = "my-project-staging" ]; then npm run build:staging elif [ "$GCLOUD_PROJECT" = "my-project-production" ]; then npm run build:production else echo "Unknown project: $GCLOUD_PROJECT" exit 1 fi
デプロイする対象プロジェクトごとにビルドコマンドを切り分けています。
Firebase Hosting の Predeploy / Postdeploy 機能を使ってコマンドが実行されている最中は環境変数$GCLOUD_PROJECT
にプロジェクトIDが入るようになっています。これを使って切り分けます。
最後にfirebase.json
にコマンドを追記します。
firebase.json
{ ... "hosting": { "public": "hostings/web/dist", ... "predeploy": "cd hostings/web && rm -rf dist && ./build_by_firebase_deploy.sh", "postdeploy": "cd hostings/web && rm -rf dist" },
predeploy / postdeploy の部分に書くコマンドはfirebase.json
があるパスで実行される形式で書きます。ビルド前とデプロイ後にdist
フォルダを消していますが、やらなくてもいいです。
これでfirebase deploy
コマンドを実行したときにデプロイ先のFirebaseプロジェクトごとに環境変数が読み込まれてビルドされるようになりました。
デプロイコマンドを打つ前に手動でビルドする方法(おすすめしない)
以下のようにスクリプトの設定をしているとします。
package.json
"scripts": { ... - "build": "astro check && astro build" + "build:base": "astro check && astro build", + "build:staging": "npm run build:base -- --mode staging", + "build:production": "npm run build:base -- --mode production" },
そしてStaging環境にデプロイしたいときは以下のコマンドを実行する。
cd hostings/web npm run build -- --mode staging firebase deploy --only hosting -P staging
そしてProduction環境にデプロイしたいときは以下のコマンドを実行する方法です。
cd hostings/web npm run build -- --mode production firebase deploy --only hosting -P production
この方法はおすすめしません。先に書いた Predeploy 機能を使うべきです。
理由は、複数コマンドを手動実行することでミスにつながりやすいからです。また、only
オプションなしのfirebase deploy
を実行するとFirebase Hostingへもデプロイされるので、他のFirestoreなどのデプロイをする際にビルドし忘れるリスクもあります。
Predeploy 機能を使わずにGithub Actionsなどでデプロイする(おすすめしない)
Github Actionsなどで自動デプロイの環境を整えるのはいいと思います。ただ、その場合もPredeploy 機能を使うべきです。
Predeploy 機能を使わないと、間違えてローカル環境でfirebase deploy
を実行したときにビルドし忘れて、古い別環境のソースコードがデプロイされる事故が発生しやすくなります。