Firebase Local Emulator Suite を使ってみた
Firebaseを使ったアプリの開発中、アプリのバグによってFirestoreへの読み取りリクエストが大量に発生し、一瞬で無料利用枠の上限に達してしまったことがあリました。
そこで、開発中にFirestoreをローカルでモックできる手段は無いか探していたところ、Firebase Local Emulator Suiteというものを見つけたので試してみました。
インストール
以下コマンドでインストールします。
sudo npm install -g firebase-tools
また、エミュレータの実行にはJava(バージョン11以降)が必要でした。事前にインストールして、javaコマンドのPATHを通しておく必要があります。
筆者は以下リンクよりJava18をインストールしました。
初期設定
初期設定をします。
firebase init
最初の選択肢で、Emulators: Set up local emulators for Firebase productsを選択しました。他にも利用するサービスとして、Hosting、Storage、Firestoreを選択しました。
Emulators Setupでは、利用するエミュレータとして、Authentication Emulator、Firestore Emulator、Hosting Emulator、Storage 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を編集します。
{
"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にあった対処方法を参考にします。
-
一度、動作しているエミュレータを停止します。(このタイミングで保存されているデータは消えますが、一旦止むなし)
-
firestore-debug.logが作成されていると思うので、削除します。 -
以下のコマンドでエミュレータを再起動します。
firebase emulators:start --import=./firebase_export --export-on-exit -
別ターミナルで再度エクスポートのコマンドを実行してみます。
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のリクエスト上限に達したり、下手に課金されたり、といったことを回避するためのツールとして重宝したいです。
Discussion