Install
npx skillscat add geckou/project-starter/deploy Install via the SkillsCat registry.
deploy
デプロイ対象の環境を確認し、scripts/deploy.sh ベースのデプロイを実行・ガイドする。
環境とコマンド
| 環境 | コマンド | 用途 |
|---|---|---|
| develop | yarn deploy:develop |
開発確認用 |
| staging | yarn deploy:staging |
リリース前検証 |
| production | yarn deploy:production |
本番(release/hotfix 後) |
部分デプロイ: bash scripts/deploy.sh <env> --only functions / --only hosting
カンマ区切りで複数指定もできる(--only functions,hosting)。
Mobile は EAS 経由(eas build + eas submit)で、deploy.sh の対象外。
⚠️ yarn firebase:deploy / yarn firebase:deploy:hosting は deploy.sh を通らない。
事前チェックも環境ごとの絞り込みもせず、apps/web/.env.local の退避もしない。そのためfirebase.json に hosting ターゲットが複数ある構成では全ターゲットに配り(今アクティブな
環境のビルドが別の環境のサイトにも出る)、サーバー秘密が SSR 関数へ同梱される。
デプロイは yarn deploy:<環境名> を使う。
deploy.sh がやること
scripts/use-env.sh <env>で.env.local(ルート +apps/web/+apps/mobile/)と Firebase プロジェクトを切り替え- あわせて
apps/web/.envを生成する(WEB_SSR_ENV_KEYS+NEXT_PUBLIC_*)。
framework-backed hosting ではこのファイルの内容が SSR 関数の環境変数になる。
SSR で読むサーバー専用の変数を足したらWEB_SSR_ENV_KEYSにも追記する
(→.claude/docs/architecture.md)
- あわせて
type-check/lint/test/buildの事前チェック(SKIP_CHECKS=1を渡したときのみ省略。CI 専用の抜け道で、ローカルでは使わない)- workspace 依存(
@geckou/*)を package.json から一時削除(Cloud Build が npm registry から取得しようとして失敗するため。終了時に自動復元) apps/web/.env.*を退避(framework-backed hosting はこれらを関数のソースへ同梱するため、全文コピーの.env.localが入るとサーバー秘密まで載る。終了時に自動復元。中断で取りこぼしても次回のデプロイで戻す)- 既定のデプロイ対象を
.firebasercから導出する(--only未指定のとき)- 複数の環境が同じ Firebase プロジェクト ID を指す構成(1 プロジェクトに環境を
相乗りさせる →.claude/docs/git-workflow.md)では、functions/firestore/storageは環境で分けられない。共有する環境のうち最も本番側の 1 つ
(通常はproduction)以外では、既定のデプロイ対象から外す - 同じ条件で、
firebase.jsonのhostingにその環境名のターゲット(target/site)が
無い場合はhostingも外す(配ると他の環境 = 本番のサイトを上書きするため)。
配る対象が全て外れた環境では、配るものが無いのでエラーで終了する
(配る側 = 通常productionはこの絞り込みを受けない) - 外した対象は
--onlyで明示すれば配れる。hostingも止めはしないが、他の環境の
サイトを上書きするため警告が出る(サイトを分けてから配ること) - 環境ごとに Firebase プロジェクトを分ける構成では何も変わらない
- 複数の環境が同じ Firebase プロジェクト ID を指す構成(1 プロジェクトに環境を
- functions / firestore → storage → framework hosting の順にデプロイ
- hosting は複数同梱だと next build がハングするため、ターゲットごとに個別デプロイする
- 配る先は環境名と一致する hosting ターゲットだけ(
firebase.jsonに複数ある場合)。
ターゲット名が環境名と無関係な構成では絞り込めず全部に配るので、DEPLOY_HOSTING_TARGETS='web admin'のように明示する - storage は Cloud Storage 未有効化時に失敗しうるため個別に実行し、失敗時は対処方法を表示する
- storage は
firebase.jsonがstorageを宣言している場合のみ対象になる。Cloud Storage を使わないプロジェクトはfirebase.jsonからstorageを削除する
--force は hosting とルールでは意図的に使っている(確認を飛ばすだけなので、外さないこと)。
functions は別扱い。 --force は「ソースに無い関数を確認なしで削除する」を含むため、
対象に functions が入るときは対話端末からの実行では付けない(削除の可否を人に聞く)。
非対話(CI)はプロンプトに答えられずデプロイが止まるので、付けたままにする。
FUNCTIONS_FORCE |
挙動 |
|---|---|
auto(既定) |
非対話なら付ける / 対話端末では付けず、削除を人に聞く |
always |
常に付ける |
never |
常に付けない |
不正な値はエラーで止まる(never のつもりの打ち間違いが、非対話で --force に
化けるのを防ぐため)。
production へのデプロイは production ブランチからのみ実行できるガードが deploy.sh に入っている。
どうしても他ブランチから実行する必要がある場合のみ FORCE_DEPLOY=1 yarn deploy:production で回避できる。
手順
ユーザーにデプロイ対象の環境を確認する
前提を確認する:
.env.<env>が存在するか(なければ.env.exampleからコピーして値を埋める)firebase login:listでログイン済みか- production の場合: 現在のブランチが
productionか(deploy.sh がガードしている。release/hotfix マージ後のデプロイが原則)
firebase experiments:enable webframeworksは deploy.sh が自動実行するため手動での有効化は不要。yarn deploy:<env>を実行する失敗したら
/troubleshootの手順で診断する403, The caller does not have permission/lacks IAM permission ...は権限不足。
どのアカウントの権限かは実行経路で違う — ローカル実行ならfirebase loginの
ユーザー(または ADC)、CI ならFIREBASE_SERVICE_ACCOUNTのサービスアカウント。
CI で出た場合は下の「CI 経由のデプロイ」のロール一覧を見る
CI 経由のデプロイ
.github/workflows/deploy.yml が push トリガーで同じ scripts/deploy.sh を実行する:
| ブランチ | デプロイ先 |
|---|---|
| release/** / hotfix/** | staging |
| production | production |
develop は CI から自動デプロイしない(複数人の feat/* push が互いに上書きし合うため)。各自 yarn deploy:develop で手動デプロイする。
CI には Secrets として FIREBASE_SERVICE_ACCOUNT(サービスアカウント JSON)と ENV_FILE_STAGING / ENV_FILE_PRODUCTION(.env の内容)が必要。
⚠️ 鍵を作る前に、そのサービスアカウントへ IAM ロールを付与する。 Firebase Console が
自動生成する firebase-adminsdk-* は既定では Admin SDK 分の権限しか持たず、そのまま CI に
入れるとデプロイが 403 で止まる(しかも足りないロールが段階的に出るため往復になる)。
付与するロールの一覧と gcloud のコマンドは .claude/docs/git-workflow.md
「CI 用 GitHub Secrets の登録」の「先にサービスアカウントへ IAM ロールを付与する」にある。
Actions 分の節約
ワークフローは 1 ジョブ構成で、チェックとデプロイを同じジョブで実行する(setup-node と yarn install の二重実行と、ジョブ単位の最低課金 1 分を避けるため)。
チェックはワークフロー側の step で実行し、deploy.sh には SKIP_CHECKS=1 を渡して二重実行を防いでいる。
デプロイ対象は push の変更差分から判定し、必要なターゲットだけを --only で渡す。apps/web/ だけの変更なら hosting だけ、firestore.rules だけなら firestore だけがデプロイされる。
影響範囲を特定できないファイル(ルート設定・packages/ 等)が含まれる場合は全ターゲットをデプロイする。
ただし CI も deploy.sh と同じ絞り込み(上の 5.)を通すため、1 プロジェクトに環境を相乗りさせる
構成では、配る側でない環境(通常は staging)から functions / firestore / storage は配られない。
デプロイが失敗した回の変更は、次の push では再送されない。 取りこぼしたときはworkflow_dispatch(Actions タブから手動実行)で全ターゲットをデプロイして回復する。
相乗り構成では、この経路でも絞り込みが効く(staging から関数やルールは配られない)。
その3つを配る必要があるなら production へのデプロイか、手元からのbash scripts/deploy.sh <環境名> --only functions,firestore,storage で配る。
ルール
- デプロイ前チェック(型・lint・テスト・ビルド)は deploy.sh が自動実行する。ローカルでスキップしない(
SKIP_CHECKS=1は CI 専用。CI ではワークフロー側の step が同じチェックを実行済み) - Firestore / Storage Rules の変更は本番データに即座に影響するため、production へのデプロイ前に差分を必ず確認する
- ルールを変更したら
yarn test:rulesを実行する(Firestore / Storage の両方を検証する) - 本番環境の
.env.productionの値が最新か確認する
派生プロジェクトへの一度きりの移行
ルールテストの実体は scripts/test-rules.sh にあり、CI(ci.yml / deploy.yml)はこれを直接呼ぶ。scripts/ も .github/workflows/ も Template Sync の対象なので、CI 側は同期だけで正しく動く。
一方 ルート package.json は Template Sync の対象外(.templatesyncignore)なので、
テンプレート更新を取り込んだ派生プロジェクトでは yarn test:rules が古いコマンドのまま残る。
ローカル実行を CI と揃えるため、一度だけ手で書き換える。
"test:rules": "bash scripts/test-rules.sh",
"format": "bash scripts/format.sh",
"format:check": "bash scripts/format.sh --check"書き換えなくても CI は正しく動く(ci.yml / deploy.yml がスクリプトを直接呼ぶため)が、
手元では yarn test:rules が Firestore しか検証せず、yarn format はpackages/ のビルド前に走って Tailwind のクラスを誤った順序に並べ替える(#110)。
なお pre-commit フック(.husky/pre-commit)は同期対象なので、
書き換えなくてもコミット時の書き換え事故は起きない。