🐣

Firebase、GitHub Actions連携

2023/09/29に公開

背景

  • 以前にReact(TypeScript) + Firebaseでメモアプリ開発でReactで作ったメモアプリをFirebaseにホスティングした
  • ただ、ホスティングの手順は以下のようになっており少々面倒(さらに言えば、これとは別にGitHubへのPushも行っている)
    • ローカルでReactをビルド(npm run build
    • firebase initを行ったディレクトリ直下の公開用ディレクトリ(dist)に、/distディレクトリの中身をコピー
    • firebase deploy コマンドでデプロイ
  • なので、GitHubにPushすると、そのままFirebaseにデプロイするようにする(GitHub Actionsを使って)

手順

Firebase公式のGitHub pull リクエストによるライブチャネルとプレビュー チャネルへのデプロイに従い作業しました。

  • firebase init hosting は実行済だったので初めに firebase init hosting:github を実行
  • GitHubのリポジトリー名を聞かれるので予め利用していたリポジトリー shoji9x9/memo-app を入力
  • Set up the workflow to run a build script before every deploy? はReactのビルドをするため Y(Yes)
  • What script should be run before every deploy?npm ci && npm run build
  • Set up automatic deployment to your site's live channel when a PR is merged?Y(Yes)
  • What is the name of the GitHub branch associated with your site's live channel?main

上記質問の意味はFirebase公式のGitHubとHostingのインテグレーションが熱いがわかりやすかったです。

上記手順の結果どうなる?

これもFirebase公式のGitHubとHostingのインテグレーションが熱いに書かれていますが、次の2つが行われます。

  • GitHub Actionsの定義ファイル(.yml)を作成してくれる
  • GitHub Actions用の認証情報を生成、登録してくれる

早速Pushしてみる

ご参考:実行時のディレクトリ構成

memo-app
├── README.md
├── package-lock.json
├── package.json
├── public
├── src
└── firebase
    ├── firebase.json

Push時に動くワークフローは?

Push時にはfirebase-hosting-merge.ymlのワークフローのみが動き、firebase-hosting-pull-request.yml(Pull request作成時にプレビューサイトにデプロイする処理)は動きませんでした(Pull requestを作成していないので当たり前ですが)。

firebase.jsonが見つからないエラーが発生

ビルド時に Error: firebase.json file not found. If your firebase.json file is not in the root of your repo, edit the entryPoint option of this GitHub action. というエラーが発生したため、firebase-hosting-merge.ymlにentryPointを追加しました。firebase-hosting-pull-request.ymlも念のため同様に修正しています。

firebase-hosting-merge.yml
# This file was auto-generated by the Firebase CLI
# https://github.com/firebase/firebase-tools

name: Deploy to Firebase Hosting on PR
"on": pull_request
jobs:
  build_and_preview:
    if: "${{ github.event.pull_request.head.repo.full_name == github.repository }}"
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: npm ci && npm run build
      - uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: "${{ secrets.GITHUB_TOKEN }}"
          firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_VITE_REACT_F4C90 }}"
          projectId: vite-react-f4c90
          entryPoint: "firebase" # ここを追加

publicディレクトリーが見つからないエラーが発生

ビルド時に "error": "Directory 'dist' for Hosting does not exist." というエラーが発生しました。firebase.jsonは以下のように定義されており、"hosting"."public" の値は
fierbase init を実行したディレクトリ(今回だとfirebase)を基準としたときの相対パスとなるため、これを "../dist"npm run build の実行結果が格納されるディレクトリ)に変更したくなります。ただ、その場合エラーとなってしまうため、反対に npm run build の実行結果を firebase/dist に格納するようvite.config.tsにoutDirを追加しました。

firebase.json
"hosting": {
    "public": "dist",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  build: {
    outDir: "firebase/dist",  // ここを追加
  },
});

デプロイはできたが実行時にエラーが発生

ブラウザのコンソールに Uncaught FirebaseError: Firebase: Error (auth/invalid-api-key). というエラーが出力されました。元々React(SPA)アプリをFirebase Hostingにデプロイなどを参考にfirebaseConfigの値は環境変数として別ファイルで管理し、そのファイルはGitHubにはPushしていませんでした。そのためこれらの値を利用できずエラーが発生していました。

Firebase apiKey ってさらしていいの? ほんとに?を見ると一応このファイルをGitHubにPushしてもよさそうではありますが、不必要なリスクは犯したくないのでNext.jsで作ったポートフォリオにLAPRASのプレビューを追加で学んだばかりのシークレットを利用することにしました。GitHubのリポジトリーのSettingsからRepository secretsを追加し、firebase-hosting-merge.ymlとfirebase-hosting-pull-request.ymlに以下のようにenvを追加しました。

firebase-hosting-merge.yml
# This file was auto-generated by the Firebase CLI
# https://github.com/firebase/firebase-tools

name: Deploy to Firebase Hosting on merge
"on":
  push:
    branches:
      - main
jobs:
  build_and_deploy:
    runs-on: ubuntu-latest
    env: # ここを追加
      VITE_FIREBASE_API_KEY: ${{ secrets.VITE_FIREBASE_API_KEY }}
      VITE_FIREBASE_AUTH_DOMAIN: ${{ secrets.VITE_FIREBASE_AUTH_DOMAIN }}
      VITE_FIREBASE_PROJECT_ID: ${{ secrets.VITE_FIREBASE_PROJECT_ID }}
      VITE_FIREBASE_STORAGE_BUCKET: ${{ secrets.VITE_FIREBASE_STORAGE_BUCKET }}
      VITE_FIREBASE_MESSAGING_SENDER_ID: ${{ secrets.VITE_FIREBASE_MESSAGING_SENDER_ID }}
      VITE_FIREBASE_APP_ID: ${{ secrets.VITE_FIREBASE_APP_ID }}
      VITE_FIREBASE_MEASUREMENT_ID: ${{ secrets.VITE_FIREBASE_MEASUREMENT_ID }}
    steps:
      - uses: actions/checkout@v3
      - run: npm ci && npm run build
      - uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: "${{ secrets.GITHUB_TOKEN }}"
          firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_VITE_REACT_F4C90 }}"
          channelId: live
          projectId: vite-react-f4c90
          entryPoint: "firebase"

今回はこのように対応しましたが、自動で登録されたシークレットFIREBASE_SERVICE_ACCOUNT_VITE_REACT_F4C90 から上記環境変数の情報を取得できそうな気もします。また調べてみます。

2023/10/1追記:上記シークレットの内容を確認したがAPI Keyなどは含まれていなかったため、当初通りAPI Keyなどを個別にシークレットに登録する必要がありそう。

コード

https://github.com/shoji9x9/memo-app

アプリケーション

https://vite-react-f4c90.web.app/

今後の予定

  • React Hook Form、Zodの利用
  • Functions、Messagingなどのまだ利用していないFirebaseの機能を試す

Discussion