🔥

Firebase Local Emulator Suite を使ってみた

2022/08/19に公開

Firebaseを使ったアプリの開発中、アプリのバグによってFirestoreへの読み取りリクエストが大量に発生し、一瞬で無料利用枠の上限に達してしまったことがあリました。

そこで、開発中にFirestoreをローカルでモックできる手段は無いか探していたところ、Firebase Local Emulator Suiteというものを見つけたので試してみました。

インストール

以下コマンドでインストールします。

sudo npm install -g firebase-tools

また、エミュレータの実行にはJava(バージョン11以降)が必要でした。事前にインストールして、javaコマンドのPATHを通しておく必要があります。

筆者は以下リンクよりJava18をインストールしました。
https://www.oracle.com/java/technologies/javase/jdk18-archive-downloads.html

初期設定

初期設定をします。

firebase init

最初の選択肢で、Emulators: Set up local emulators for Firebase productsを選択しました。他にも利用するサービスとして、HostingStorageFirestoreを選択しました。

Emulators Setupでは、利用するエミュレータとして、Authentication EmulatorFirestore EmulatorHosting EmulatorStorage Emulatorを選択しました。
各エミュレータが利用するポートはデフォルトのまま、Would you like to enable the Emulator UI? の質問についてはこの時点ではよく分からなかったので、Yとしておきました。

その他の設定は基本デフォルトでよしなに設定しました。

エミュレータの開始

以下のコマンドで開始します。

firebase emulators:start
  • 2022/9/1追記
    データをエクスポートできるようにするため、以下のコマンドの方が良いです。

    firebase emulators:start --import=./firebase_export --export-on-exit
    

すると、以下のように出力されました。

i  emulators: Starting emulators: auth, firestore, hosting, storage
i  firestore: Firestore Emulator logging to firestore-debug.log
i  emulators: Shutting down emulators.
i  firestore: Stopping Firestore Emulator
i  auth: Stopping Authentication Emulator
i  storage: Stopping Storage Emulator
i  hub: Stopping emulator hub
⚠  hosting: Port 5000 is not open on localhost, could not start Hosting Emulator.
⚠  hosting: To select a different host/port, specify that host/port in a firebase.json config file:
      {
        // ...
        "emulators": {
          "hosting": {
            "host": "HOST",
            "port": "PORT"
          }
        }
      }
i  emulators: Shutting down emulators.

Error: Could not start Hosting Emulator, port taken.

5000番ポートが使えないとのことだったので、firebase.jsonを編集します。

firebase.json
{
  "emulators": {
    "auth": {
      "port": 9099
    },
    "firestore": {
      "port": 8080
    },
    "hosting": {
-      "port": 5000
+      "port": 15000
    },
    "storage": {
      "port": 9199
    },
    "ui": {
      "enabled": true
    }

再度、開始すると上手く行きました。

i  emulators: Starting emulators: auth, firestore, hosting, storage
i  firestore: Firestore Emulator logging to firestore-debug.log
i  hosting: Serving hosting files from: public
✔  hosting: Local server: http://localhost:15000
i  ui: downloading ui-v1.9.0.zip...
Progress: =====================================================================================================================================> (100% of 4MB)
i  ui: Emulator UI logging to ui-debug.log

┌─────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! It is now safe to connect your app. │
│ i  View Emulator UI at http://localhost:4000                │
└─────────────────────────────────────────────────────────────┘

┌────────────────┬─────────────────┬─────────────────────────────────┐
│ Emulator       │ Host:Port       │ View in Emulator UI             │
├────────────────┼─────────────────┼─────────────────────────────────┤
│ Authentication │ localhost:9099  │ http://localhost:4000/auth      │
├────────────────┼─────────────────┼─────────────────────────────────┤
│ Firestore      │ localhost:8080  │ http://localhost:4000/firestore │
├────────────────┼─────────────────┼─────────────────────────────────┤
│ Hosting        │ localhost:15000 │ n/a                             │
├────────────────┼─────────────────┼─────────────────────────────────┤
│ Storage        │ localhost:9199  │ http://localhost:4000/storage   │
└────────────────┴─────────────────┴─────────────────────────────────┘
  Emulator Hub running at localhost:4400
  Other reserved ports: 4500

Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.

試しに、FirestoreのEmulator UI(http://localhost:4000/firestore)にアクセスしてみると、以下のような画面が開きました。
こちらの画面で、実際のFirestoreのUIと同じようにテストデータの作成を行うことができます。

エミュレータの利用方法

コード内でエミュレータを利用するには、以下のように書きます。
ポイントは、最後にconnect~~Emulatorを呼び出すことです。

import { initializeApp } from "firebase/app";
import { connectAuthEmulator, getAuth } from "firebase/auth";
import { connectFirestoreEmulator, getFirestore } from "firebase/firestore";

const firebaseConfig = {
   <キー情報のため省略>
};

const app = initializeApp(firebaseConfig);

export const db = getFirestore(app);
export const auth = getAuth(app);

connectFirestoreEmulator(db, "localhost", 8080);
connectAuthEmulator(auth, "http://localhost:9099");

利用するエミュレータによって、引数の指定方法が若干異なっています。

これで、コード内でFirebaseのAPIを実行する際に、ローカルで起動したエミュレータを使ってくれるようになりました。

(2022/9/1追記)データのインポート・エクスポート

エミュレータを停止すると、エミュレータ上で作成されたデータは破棄されます。
そのため、一度作成したデータを保存しておくには、データのエクスポートが必要です。

以下のコマンドでデータをエクスポートできます。

firebase emulators:export ./firebase_export/

と思って実行したのですが、以下のようなエラーが発生しました。

Error: Did not find any running emulators for project 

こちらのissueにあった対処方法を参考にします。

  1. 一度、動作しているエミュレータを停止します。(このタイミングで保存されているデータは消えますが、一旦止むなし)

  2. firestore-debug.logが作成されていると思うので、削除します。

  3. 以下のコマンドでエミュレータを再起動します。

    firebase emulators:start --import=./firebase_export --export-on-exit
    
  4. 別ターミナルで再度エクスポートのコマンドを実行してみます。

    firebase emulators:export ./firebase_export/
    

エクスポートに成功しました。

次回起動時に、データをインポートして起動するには、同様に以下のコマンドで起動します。

firebase emulators:start --import=./firebase_export --export-on-exit

ちなみに、--export-on-exitオプションを指定することで、エミュレータの停止時に自動的にデータがエクスポートされるようになります。エクスポート先は--importに指定したディレクトリです。

(2022/10/17追記)エミュレータ停止時の不具合

Ctrl+Cでエミュレータを停止すると、たまにエミュレータが正常に停止せず、次回起動時に以下のようなエラーメッセージが表示されることがありました。

Error: Could not start Firestore Emulator, port taken.

一次対処的ではありますが、以下コマンドで直接プロセスを落とすことで、再度エミュレータを起動できるようになります。
※ポート番号は、firebase.jsonに記述したものを指定します。

lsof -t -i:8080 -i:15000 -i:9099 -i:9199 | xargs kill -9

まとめ

Firebase Local Emulator Suiteを使ってみました。
アプリの開発中に、Firebase APIのリクエスト上限に達したり、下手に課金されたり、といったことを回避するためのツールとして重宝したいです。

GitHubで編集を提案

Discussion