🔥

Firebase (v9) を利用してサクッと React アプリを作って公開する【支払い情報登録不要】

2024/02/02に公開

前書き

筆者はあまりクラウドサービスに詳しくなく、初心者による記事である。間違った記述があるかもしれないので指摘してくれるとありがたい。
おそらく他に良い構成があると思うが、今回は Firebase (v9) を使ってみた記録である。
またセキュリティについては一切考慮していない。
はじめて Firebase を触ってみる人に向けて記述しているつもりである。

対象読者

  • フロントエンドだけでお金かけずアプリ作りたい人
  • 文化祭とかのイベントでの一時的な公開などで、プロトタイプ等としてサクッと作りたい人
  • 何らかの諸事情でどうしても支払い情報を登録したくない人

はじめに

「クラウドサービス便利だよね。サーバーレスだし。なんかかっこいいし。」
という気持ちで色々調べていくとさまざまなサービスがあり、その中にもいろんなプランや機能があって、調べるほどわからなくなる。無料枠があるといっても支払い方法登録しないと使えないとかもあったりで、そもそもクレジットカードとか持ってないという学生等もいるだろう。とりあえず何か作ってみたいし、できたら公開したいだけなのだ。
また、ただ「アプリ制作」に興味があるのであって、APIサーバーとかのバックエンドを一旦棚に上げておきたい。

そんなあなたに、 Firebase という選択肢

Google が提供しているクラウドサービス Firebase というものがある。(立ち位置的には BaaS だろうか。) Firebase の Spark プランであれば支払い方法登録なしで利用できる。あんまり支払い方法を登録したくない学生や個人にとってとてもありがたい。Firebase Hosting によるホスティングサービスも使えて、ドキュメント型 NoSQL のデータベースである Firestore も以下の範囲で利用できる。マイクロなものを作る分なら困らなそうだ。

Firestore 制限項目 制限内容
保存済みのデータ 合計1GiB
下り(外向き)ネットワーク 10GiB / 月
ドキュメントの書き込み 2万件 / 日
ドキュメントの読み取り 5万件 / 日
ドキュメントの削除 2万件 / 日

(2024/2/2 時点)

https://firebase.google.com/
https://firebase.google.com/pricing

Firebase で Web アプリを作ってみる

今回は入門として静的サイトのデプロイから始めて Firestore をほんのちょっとだけ使った「タイトル争奪戦」というしょうもない Web アプリを作ってみる。サイトの真ん中にある「タイトル」をただ書き換えられるだけのアプリである。

書き換える前
書き換えた後

本記事ではこのアプリを TypeScript + React + Vite で構築する。ソースコードは GitHub で管理する。

静的サイトの手動デプロイまで一気に駆け抜ける

え、アプリって聞いたんですけど・・・?と思われるかもしれないが、まずは静的サイトを Firebase Hosting で公開するまでやる。これができればあとは配信するコンテンツを変えるだけである。

リポジトリの準備

まずは GitHub 上で、適当な名前で private リポジトリを作成する(以降このリポジトリ名をfirebase-testとする)。そしてそれをローカル環境にgit cloneしてくる。

ローカル環境の準備

開発環境として Node.js が必要だが、それを直接インストールするのではなく node のバージョン管理ツールであるvoltaを導入しておく。特に様々なプロジェクトをPC内に同居させているとバージョン管理が後々大変になるので導入しておくと良い。
https://docs.volta.sh/guide/getting-started
https://zenn.dev/aiueda/articles/7dcecaa05d4f24

React のプロジェクトの作成

TypeScript + React + Vite のプロジェクトを作成する。ありがたいことに Vite にはそれを作成する公式コマンドが用意されているのでそれを使う。
まず、cloneしてきたfirebase-testのフォルダにターミナルから入って、以下のコマンドを入力する。

npm create vite@latest . -- --template react-swc-ts

不慣れな場合はnpm create vite@latestでインタラクティブに操作できる。ただしプロジェクト名を指定せずにカレントディレクトリ.を指定する必要がある。

これができたら以下のコマンドで開発サーバーが立ち上がるか確認しよう。

npm install
npm run dev

そうすると http://localhost:5173 にアクセスすれば "Vite + React" と書かれたページが表示されるはずである。
ここまでを一旦commitしておこう。

Firebase のプロジェクト作成

ここからは一旦ソースコードから離れて Firebase の Web サイト上で操作をする。まずトップページから [使ってみる] というボタンがデカデカとあるはずなのでそれを押す。すでに Google アカウントにログイン済みであれば、Google アカウントの認証画面をスキップしてコンソール画面が映し出されると思われる。Firebase が Google のサービスなので Google アカウントがあるとここらへんはややこしい手続きもなく相当スムーズに進める。

それでは [プロジェクトを作成] というボタンがあるのでそれを押す。
Firebaseのプロジェクト作成

そのあとプロジェクト名やら Google アナリティクスの有効化やら聞かれる。今回の場合は Google アナリティクスについてはどっちでも良いが、どうせなら有効にしておいた方が良い。
最後に [プロジェクトを作成] のボタンを押してプロジェクトが作られる。
待機していれば以下の切り抜き部分を含む画面が現れるはずだ。
Firebaseプロジェクトページ

このページにあるようにアプリの追加を促してくる。今回は Web アプリなので真ん中の Web ボタンを押す。
アプリ登録画面に移動するので、そこでアプリのニックネームを入力する。"このアプリの Firebase Hosting も設定します。" というところをチェックする。するとURLの入力があるが、ここではデフォルト(おそらくプロジェクトID)を選択しておくのが無難である。あとは [アプリを登録] ボタンを押して設定完了である。それ以降は Firebase を利用する手順が書いてあるが、この記事で説明するのでスキップしていって構わない。

React プロジェクト上での Firebase 設定

これでようやく準備が整いつつあるが、ローカル環境側の準備をもう少ししなければならない。
ローカルの開発環境(firebase-testフォルダ)に戻って、そこで以下のコマンドを実行する。

npm install firebase
npm install -g firebase-tools

firebaseの方はスクリプトから Firebase を操作するのに必要な物が入ったライブラリであり、firebase-toolsは Firebase の CLI ツールである。
次に以下のコマンドで Google アカウントのログインを行なう。

firebase login

ログインできたら firebase hosting 用の設定を以下のコマンドから行う。

firebase init hosting

さて、ここからは Firebase CLI からの質問攻めにあう。

? Please select an option: (Use arrow keys)
❯ Use an existing project 
  Create a new project 
  Add Firebase to an existing Google Cloud Platform project 
  Don't set up a default project 

初回のみ上のような質問がされるが、すでに Firebase 上でプロジェクトを作っているのでUse an existing projectを選び、次にどのプロジェクトか選択するように言われるので、先ほど作ったプロジェクトを選ぶ。

? What do you want to use as your public directory?

ざっくりいうと今あるどのディレクトリを静的サイトのルートにしたいのかということだ。ここにはビルド済みファイルを入れる必要がある。ここはとりあえずdist[1]と入力しよう。

? Configure as a single-page app (rewrite all urls to /index.html)?

yesを解答しておこう。少なくとも今我々は React を使っていて single-page app (SPA) である。noにしても動くが、例えば React Router とかを使おうとするとここらへんの恩恵を受ける。

? Set up automatic builds and deploys with GitHub?

とてもありがたいことにデプロイ用の GitHub Actions ワークフローを生成してくれる。のちのちここら辺を改めて操作するが、一旦手動デプロイのテストをしたいためnoにする。
(もちろん「手動デプロイ?知るかよ!」という人はここをyesで回答してfirebase init hosting:githubの項目を先取りして見ると良い。)

そうすると.firebasercファイルとfirebase.jsonファイルが生成されるはずだ。
ここらへんで設定を間違えたとしたら Vite の公式を参考にすれば大丈夫だし、再度firebase init hostingすれば再設定できる。

ここまで終わったらcommitして GitHub にpushしておき、そしていよいよデプロイだ。

手動デプロイ

デプロイするためにはまず React アプリをビルドしないといけないので以下のコマンドを実行する。

npm run build

そうするとdistフォルダが生成されたはずだ。あとは以下のコマンドでデプロイする。

firebase deploy

やったね!これでもうサイト自体は公開された。
Firebase コンソール上で Web アプリを追加する際 URL を設定するところがあったが、あそこがデフォルトであればhttps://{プロジェクトID}.web.appにホスティングされているはずだ。

自動デプロイ

でも、毎回npm run buildしてfirebase deployを手元でするの面倒だし、怖い!
そんなあなたに朗報、 Firebase はその自動化ワークフローを用意してくれている。それがさっき触れた? Set up automatic builds and deploys with GitHub?yesと回答した時だ。すでにnoと回答していても以下のコマンドを実行すれば同じ挙動になる。

firebase init hosting:github

そうすると GitHub のログインや Firebase への権限の許可等をやるよう指示される。完了したら再びコマンドラインに戻ってこよう。ログインに成功したら以下の質問が出ているはずだ。

? For which GitHub repository would you like to set up a GitHub workflow? (format: user/repository)

これはデフォルト値が現在のリポジトリなのでそのまま Enter を押す。そうすると GitHub から デプロイできるように GitHub 側の設定をしてくれる。

? Set up the workflow to run a build script before every deploy?

この質問はデプロイワークフローにビルドを含むかどうか聞かれていて、Reactはビルド必須なのでyesと回答する。

? What script should be run before every deploy?

そのあと、どんなスクリプト実行するか聞かれるが、デフォルトのnpm ci && npm run build[2]で良いのでただ Enter を押す。

? GitHub workflow file for PR previews exists. Overwrite? firebase-hosting-pull-request.yml

おそらくひとりでの開発であればnoだろうが、Pull Request (PR) 時にプレビュー用のサイトを用意するワークフローである。多人数であればローカルにpullしてこなくてもサイトを確認できるのでめちゃくちゃ便利。ここは機能検証も兼ねてyesにしておこう。そうすると./github/workflows/firebase-hosting-pull-request.ymlが生成される。

? Set up automatic deployment to your site's live channel when a PR is merged?

PR をマージしたあと本番用にデプロイするか聞かれていて、yesにしておく。

? What is the name of the GitHub branch associated with your site's live channel

どのブランチにマージされた時かと聞かれていて、デフォルトはmainであり、今回もそれに従う。そうすると./github/workflows/firebase-hosting-merge.ymlが生成される。

実際に自動デプロイを動かしてみる

さてdevブランチを切って、App.tsxの中身を適当に書き換える。

App.tsx
import "./App.css";

function App() {
  return (
    <>
      <div>
        <h1>Firebase、マジ神</h1>
      </div>
    </>
  );
}
export default App;

これをcommit&pushして GitHub から PR を作成する・・・前に、このままだと権限で PR 時のワークフローがうまくいかなかったりするので、少しだけ以下の記事に従って GitHub 上の設定を見直す。

GitHub のリポジトリの Settings→Actions→General の Workflow permissions で Read and Write Permissions を選択する。Allow Github Actions to create and approve pull requests も選択する。

https://qiita.com/Kobayashi-Kei/items/8a436955f9123b939531

これでdevからmainへの PR を作成する。だがすぐにマージをしないでほしい。待っていると PR 時に GitHub Actions が走り、一時的なプレビューサイトを準備してその URL を貼り付けてくれる。レビュワー大歓喜である。

あとは PR をマージして少し待つと公開サイトの中身が切り替わっていることが確認できる。

自動デプロイ後のサイト

これで自動デプロイのワークフローができた。

いよいよ Web アプリを作ってみる

静的サイトを Firebase Hosting にデプロイする話をしてきたが、実のところ Web アプリの話ではなかった。ここからようやく Web アプリの構築である。だが安心してほしい。ここまできたらあと1割と言っても良い。

というわけでここから「タイトル争奪戦」というアプリを作ってみる。
タイトル部分を書き換えるだけのなんの面白みもないアプリである。しかし Firestore というデータベースを操作するので立派な Web アプリである。
(この後の作業でワークフローの修正があるので、devブランチを切ってやると良い。)

基本的な動作の実装

まずは Firestore との接続の前にuseStateを使って実装したい動きを作る。

App.tsx
import { useState } from "react";
import "./App.css";

function App() {
  const [title, setTitle] = useState("Firebase、マジ神");
  const [userTitle, setUserTitle] = useState("");

  // ユーザー入力のハンドリング
  function handleOnChangeUserTitle(newTitle: string) {
    setUserTitle(newTitle);
  }

  // タイトルの変更
  function handleOnSendTitle() {
    setTitle(userTitle);
    setUserTitle("");
  }

  return (
    <>
      <div>
        タイトル争奪戦
        <h1>{title}</h1>
        <div
          style={{
            display: "flex",
            flexDirection: "row",
            justifyContent: "center",
            alignItems: "center",
            gap: 10,
          }}
        >
          <input
            type="text"
            id="new-title"
            name="new-title"
            value={userTitle}
            onChange={(e) => handleOnChangeUserTitle(e.target.value)}
          />
          <input
            type="button"
            id="change-title"
            name="change-title"
            value="書き換える"
            minLength={50}
            onClick={() => handleOnSendTitle()}
          />
        </div>
      </div>
    </>
  );
}

export default App;

これで基本的な動きはできた。npm run devで確認しておくと今のままではタイトルの変更は別ブラウザ、別PCには共有されない。
基本的な動きの実装

Firestore の準備

Firestore を使う前に Firebase のコンソールで少し作業をする。左側のメニューから [構築] > [Firestore Database] を選ぶ。
メニューからFirestore

すると以下のような Firestore のページに移動するので [データベースの作成] を押す。
Firestoreトップ

そうするとデータベースのロケーションやセキュリティルールを設定する画面が出る。ロケーションは今回の場合はどこでも良いが、参考までに公式ドキュメントを見ておくと良い。セキュリティルールについては「テストモードで開始する」を選ぶと手っ取り早いが、後でちゃんと設定しておくのが良い。
Firestoreポップアップ

これで Firestore が使える状態になった。
Firestore準備完了

Firestore の導入

ここから Firestore と React アプリとを繋げる。

Firestore との接続にはいくつかの値が必要になる。まずは Firebase のプロジェクトトップから、プロジェクト名の下にある登録した Web アプリ をクリックする。

Firebase Webappへ

そうすると下の方に API key などが書かれたコードブロックがある。緑で塗られた位置にある値が Firestore (というよりもこのプロジェクトのリソース)に接続するために必要だ。このコードブロックはコピーできるが、この手の値は環境変数にしておいた方が良い。

必要な値

よって、上の画像で塗りつぶした値を環境変数として登録する。なおリポジトリにこれらの環境変数があるのは望ましくないので、ファイル名を.env.localにしておく。"xxx"の部分をそれぞれ対応する値に書きかえて使って欲しい。

.env.local
VITE_FIREBASE_API_KEY="xxx"
VITE_FIREBASE_AUTH_DOMAIN="xxx"
VITE_FIREBASE_PROJECT_ID="xxx"
VITE_FIREBASE_STORAGE_BUCKET="xxx"
VITE_FIREBASE_MESSAGING_SENDER_ID="xxx"
VITE_FIREBASE_APP_ID="xxx"
VITE_FIREBASE_MEASUREMENT_ID="xxx"

そして 新たに src/firebaseApp.tsファイルを作り読み込み設定をする。

firebaseApp.ts
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";

const firebaseConfig = {
  apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
  authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
  projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
  storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
  appId: import.meta.env.VITE_FIREBASE_APP_ID,
  measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID
};

const app = initializeApp(firebaseConfig);
const database = getFirestore(app);

export { database };

そしてApp.tsxを Firestore のデータベースとの更新部分を足して作り替える。

App.tsx
- import { useState } from "react";
+ import { useState, useEffect } from "react";
  import "./App.css";
+ import { doc, setDoc, onSnapshot } from "firebase/firestore";
+ import { database } from "./firebaseApp";

+ const COLLECTION_NAME = "title";  // コレクション名
+ const UNIQUE_DATA_ID = "unique";  // ドキュメントID

  // Firestore に格納されるデータの型定義
+ type Data = {
+   title: string;
+ };

  // Firestore 上のタイトルデータを更新する
+ function updateData(newTitle: string) {
+   const dataDoc = doc(database, COLLECTION_NAME, UNIQUE_DATA_ID);
+   const data: Data = {
+     title: newTitle,
+   };
+   setDoc(dataDoc, data);
+ }

  function App() {
    const [title, setTitle] = useState("Firebase、マジ神");
    const [userTitle, setUserTitle] = useState("");

    // ドキュメントリスナーの生成
+   useEffect(() => {
+     const dataDoc = doc(database, COLLECTION_NAME, UNIQUE_DATA_ID);
+     const unsubscribe = onSnapshot(dataDoc, (snapshot) => {
+       if (snapshot.exists()) {
+         const data = snapshot.data() as Data;
+         setTitle(data.title);
+       }
+       return () => unsubscribe();
+     });
+   }, []);

    // ユーザー入力のハンドリング
    function handleOnChangeUserTitle(newTitle: string) {
      setUserTitle(newTitle);
    }

    // タイトルの変更
    function handleOnSendTitle() {
-     setTitle(userTitle);
+     updateData(userTitle);
      setUserTitle("");
    }

    return (
      <>
        <div>
          タイトル争奪戦
          <h1>{title}</h1>
          <div
            style={{
              display: "flex",
              flexDirection: "row",
              justifyContent: "center",
              alignItems: "center",
              gap: 10,
            }}
          >
            <input
              type="text"
              id="new-title"
              name="new-title"
              value={userTitle}
              onChange={(e) => handleOnChangeUserTitle(e.target.value)}
            />
            <input
              type="button"
              id="change-title"
              name="change-title"
              value="書き換える"
              minLength={50}
              onClick={() => handleOnSendTitle()}
            />
          </div>
        </div>
      </>
    );
  }

  export default App;
Firestore との連携部分の解説

今回は単一のドキュメントのみで制御しており、極めてシンプルな構成である。以下の三つの要素だけで成り立っている。

  • doc
    DocumentReferenceを生成する関数。DocumentReferenceはドキュメントの住所情報だと思えば良い。docの引数はデータベース情報、コレクション名、ドキュメントIDが必要。
    ドキュメントではなくCollectionReferenceが必要であればcollectionがある。
  • setDoc
    データをセットする関数。ドキュメントが存在しない場合は作成してくれる。更新も兼ねているが、実際にはupdateDocとちゃんと使い分けた方が良いと思われる。
    また似たものでaddDocというものがある。setDocDocumentReferenceが第一引数でありドキュメントIDが必要で、被りがあれば上書きする。addDocCollectionReferenceが第一引数で、ドキュメント名を重複しない名前で自動採番し必ず新しいドキュメントを生成する。
  • onSnapshot
    第一引数で指定されたドキュメントのデータ変更を監視し、更新を検知すると第二引数の関数を発火するリスナーを作ってくれる関数。返り値はリスナーを停止する関数。リアルタイムアップデートを実現する今回の要。

https://zenn.dev/nash/articles/6e18bd94eca63e
https://firebase.google.com/docs/firestore
https://firebase.google.com/docs/firestore/query-data/listen

`useEffect`について

特にドキュメントリスナーの生成は(コンポーネント内部の値に依存しない限り)最初の一回限りで良い。これを実現するのが以下の形である。

useEffect(() => {
  // set up
  return () => {
    // clean up
  }
}, [])

useEffectの第二引数は依存配列と呼ばれ、この依存配列の中身に変更があれば第一引数の関数が発火する仕組みである。空の配列[]を指定することで最初の一回以降変更が起こることがないため、最初の一回だけ呼ばれるようになる。ちなみにuseMemoと混同されがちだが、React の公式説明を見れば位置付けが全く異なるので注意すること。
正確で詳しい情報は React の公式ドキュメントを参照するに越したことはない。
https://ja.react.dev/reference/react/useEffect
https://ja.react.dev/learn/synchronizing-with-effects
https://ja.react.dev/learn/lifecycle-of-reactive-effects#what-an-effect-with-empty-dependencies-means

npm run devで開発サーバーを立ち上げ、二つのブラウザウィンドウを起動。そして片方のブラウザからタイトルを変更した時に、もう一つのタイトルが変更されれば成功である。

書き換える前
書き換えた後

Firestore のデータベースの中身を確認すると、titleコレクションのuniqueというデータがちゃんと入っているのが確認できる。

データベースの確認

いざデプロイ! のはずが

さて、これであとは PR してmainブランチにマージすれば.github/workflows/firebase-hosting-merge.ymlのワークフローが動いてデプロイしてくれる・・・と言いたいところだが、このままでは環境変数が解決できずうまくいかない。

試しに手元で.env.localのファイル名を.env.ignoreに書き換えてnpm run build && npm run previewを実行してみると良い。一見正しく動いているように見えるが、Firestore のデータが参照されておらずタイトルの書き換えが反映されない。実際検証ツールでみるとエラーが出ており Firestore にアクセスできていない。
先ほど書き換えた.env.ignore.env.localに戻して、再度npm run build && npm run previewしてみよう。すると期待通り動くことがわかる。

さて、重要なのは.env.localに定義された環境変数がビルド時に存在するかどうかだ。
しかし、今 GitHub 上にこのファイルは存在しない。一つの解決策として.env.local.envにファイル名を変えれば Git の管理対象になるので GitHub 上に置くことができ、問題なくビルドできるようになるが、それは避けたい。

GitHub secrets の登録とワークフローの修正

ということで、ワークフローの修正と GitHub 上の操作を通してこれを解決したい。
まずは GitHub 上での操作を行う。要は GitHub 上のどこかにそれがあれば良いのだ。
GitHub にはsecretsという機能がある。
https://docs.github.com/ja/actions/security-guides/using-secrets-in-github-actions

シークレットは、組織、リポジトリ、またはリポジトリ環境内に作成する変数です。作成したシークレットは、GitHub Actionsワークフローで利用できます。 GitHub Actions でシークレットを読み取ることができるのは、シークレットをワークフローに明示的に含める場合のみです。

つまりワークフロー上で参照できるが、一度登録すれば簡単には中身が見えないようになる機能だ。
GitHub の「リポジトリのシークレットの作成」の項を参照しながら.env.localに書いた環境変数を一つずつ加えていく。(secretsの登録名として冗長なVITE_部分は消しても良いが、この後のワークフローの修正時はsecrets.以下を自身が設定したものに読み替えて修正してほしい。)

さて、あとはワークフローからこれを参照すれば良いが、必要なステップはnpm ci && npm run buildのところなので、そこにenv:を利用して環境変数を流す。

.github/workflows/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
    workflow_dispatch:
  jobs:
    build_and_deploy:
      runs-on: ubuntu-latest
      steps:
        - uses: actions/checkout@v4
        - run: npm ci && npm run build
+         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 }}
        - uses: FirebaseExtended/action-hosting-deploy@v0
          with:
            repoToken: "${{ secrets.GITHUB_TOKEN }}"
            firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_(your-project-id) }}"
            channelId: live
            projectId: (your-project-id)

.github/workflows/firebase-hosting-pull-request.ymlが残っているのであれば、そちらの方も忘れずに修正しよう。
あとはmainブランチにpushすれば、ワークフローがトリガーされて自動的にデプロイまでしてくれる。
実際にホスティングされている URL にアクセスすれば想定通り動いてくれることがわかるだろう。

おめでとう! これで Firebase を利用した Web アプリが公開できた!

Firestore というデータベースを利用した正真正銘の動的サイトであり、しかも公開もできるようになった。
少なくともここまでの内容を知っていれば大体の小規模アプリは作れるようになるはずだ。

(おまけ) Firebase Hosting を停止する方法

ローカルの開発環境で良いのでfirebase hosting:disableを実行する。すると

? Are you sure you want to disable Firebase Hosting for the site プロジェクト名
This will immediately make your site inaccessible! (Y/n)

と聞かれるので、yesと回答すると停止できる。

脚注
  1. 何も入力しないとデフォルトでpublicが指定される。しかし、npm run buildにおけるviteの動作はdistフォルダに生成される。もちろん vite.config.tsoutDirにちゃんと指定すれば好きな値を入れれば良い。publicはどちらにせよviteのプロジェクトの構成と干渉するので避けた方が良い。(すでにpublic/vite.svgがあるだろう。) ↩︎

  2. npm cinpm installの亜種でciは clean install の意味らしい。(参考↩︎

Discussion