もふもふ技術部

IT技術系mofmofメディア

Expo, React Native, FirebaseでローカルのFirestoreエミュレータに接続する

個人で開発しているアプリで、Firestoreにつないだテストを実行したいなと思ったので、ローカルでのテストはFirebaseのエミュレータを使えば良いのではないかと考えた。Firebaseのエミュレータを使ったことがないので試しに使ってみます。

アプリケーションを作る

blank (TypeScript)でプロジェクトを生成します。

 $ expo init firebase-test
┌─────────────────────────────────────────────────────────────────────────┐
│
       │
│   There is a new version of expo-cli available (4.13.0).
       │
│   You are currently using expo-cli 4.4.7
       │
│   Install expo-cli globally using the package manager of your choice;   │
│   for example: `npm install -g expo-cli` to get the latest version      │
│
       │
└─────────────────────────────────────────────────────────────────────────┘
✔ Choose a template: › blank (TypeScript)    same as blank but with TypeScript configuration
✔ Downloaded and extracted project files.
🧶 Using Yarn to install packages. Pass --npm to use npm instead.
✔ Installed JavaScript dependencies.

✅ Your project is ready!

To run your project, navigate to the directory and run one of the following yarn commands.

- cd firebase-test
- yarn start # you can open iOS, Android, or web from here, or run them directly with the commands below.
- yarn android
- yarn ios # requires an iOS device or macOS for access to an iOS simulator
$ cd firebase-test   
$ expo start

ちゃんと表示された。

スクリーンショット 2021-12-10 163107

Firestoreからデータを取得する

以前にやったことがあるのですが、どうやらFirebaseのパッケージがアップデートされてデータの取得や更新などの書き方が変わったようです。WEB上の情報は旧バージョンの書き方が多いのですが、公式に新バージョンの書き方が載っているので問題ない。

https://firebase.google.com/docs/web/setup

パッケージをインストールします。

$ expo install firebase

App.jsx

import { StatusBar } from 'expo-status-bar';
import React, { useEffect } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { fetchRamen } from './fetchRamen';

export default function App() {
  useEffect(() => {
    console.log('hogehoge')
    fetchRamen()
  }, [])

  return (
    <View style={styles.container}>
      <Text>Open up App.tsx to start working on your app!</Text>
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

Firebaseプロジェクトは既に作ってある前提。Firebaseコンソール画面へいけばapiKeyなどのconfig情報が取得できるので各自環境の情報を入力ください。

firebase.ts

import { initializeApp } from 'firebase/app';

export const initializeFirebase = () => {
  const firebaseConfig = {
    apiKey: "...",
    authDomain: "...",
    databaseURL: "...",
    projectId: "...",
    storageBucket: "...",
    messagingSenderId: "...",
    appId: "..."
  }

  initializeApp(firebaseConfig)
}

fetchRamen.ts

import { collection, getDocs, getFirestore } from 'firebase/firestore';
import { initializeFirebase } from './firebase';

initializeFirebase()

export const fetchRamen = () => {

  const firestore = getFirestore();
  const coll = collection(firestore, 'ramens') 
  getDocs(coll).then(snapshot => {
    snapshot.docs.map(doc => {
      console.log(doc.data())
    })
  })
}

ちゃんとデータが取得できている。

このデータは他の個人的なプロジェクトで使ってるラーメン屋情報を表示している。

スクリーンショット 2021-12-10 163042

ローカルのFirebaseエミュレータからデータを取得する

エミュレータを使える環境を作ります。

$ firebase init emulators             

     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

You're about to initialize a Firebase project in this directory:

  /home/aharada/source/firebase-test

=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add,
but for now we'll just set up a default project.

? Please select an option: Use an existing project
? Select a default Firebase project for this directory: your-project-name (YourProjectName)
i  Using project your-project-name

=== Emulators Setup
? Which Firebase emulators do you want to set up? Press Space to se
lect emulators, then Enter to confirm your choices. (Press <space>
to select, <a> to toggle all, <i> to invert selection)

i  Writing configuration info to firebase.json...
i  Writing project information to .firebaserc...

✔  Firebase initialization complete!

firebase.json

エミュレータで使うサービスを記述します。

{
  "emulators": {
    "firestore": {
      "name": "firestore",
      "host": "localhost",
      "port": 8080
    }
  }
}

エミュレータを起動する。

$ firebase emulators:start
i  emulators: Starting emulators: firestore
⚠  firestore: Did not find a Cloud Firestore rules file specified in a firebase.json config file.
⚠  firestore: The emulator will default to allowing all reads and writes. Learn more about this option: https://firebase.google.com/docs/emulator-suite/install_and_configure#security_rules_configuration.
i  firestore: downloading cloud-firestore-emulator-v1.13.1.jar...
Progress: =========================================> (100% of 61MB
i  firestore: Firestore Emulator logging to firestore-debug.log
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://127.0.0.1:4000                │
└─────────────────────────────────────────────────────────────┘

┌───────────┬────────────────┬─────────────────────────────────┐
│ Emulator  │ Host:Port      │ View in Emulator UI             │
├───────────┼────────────────┼─────────────────────────────────┤
│ Firestore │ 127.0.0.1:8080 │ http://127.0.0.1:4000/firestore │
└───────────┴────────────────┴─────────────────────────────────┘
  Emulator Hub running at 127.0.0.1:4400
  Other reserved ports: 4500

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

http://127.0.0.1:4000/firestore を開くとfirebaseのコンソールみたいのが起動できるようになるので適当にramensを登録する。

スクリーンショット 2021-12-10 163017

ソースコードは以下一行を追加するだけ

connectFirestoreEmulator(firestore, 'localhost', 8080);

fetchRamen.ts

import { collection, connectFirestoreEmulator, getDocs, getFirestore } from 'firebase/firestore';
import { initializeFirebase } from './firebase';

initializeFirebase()

export const fetchRamen = () => {

  const firestore = getFirestore();
  connectFirestoreEmulator(firestore, 'localhost', 8080);

  const coll = collection(firestore, 'ramens') 
  getDocs(coll).then(snapshot => {
      snapshot.docs.map(doc => {
      console.log(doc.data())
      })
  })
}

ローカルのデータが取れたああああ

スクリーンショット 2021-12-10 173427

どうやらエミュレータは停止すると手動で登録したデータもクリアされるっぽい。テスト環境としては好都合。