[メモ]FirebaseのFirestore DatabaseとFunctionsの開発環境構築からデプロイまで

# 環境
Firestore Database
Firebase Functions　1st gen
firebaseコマンド 11.21.0
macOS Big 11.7.4

:::note info
Firebaseで使用できるFunctionsの2nd genがpublic previewになっいる
https://firebase.google.com/docs/functions/beta
:::

# プロジェクトの作成
URL: https://console.firebase.google.com/

:::note info
・この記事に掲載しているprojectは記事用に作成したものですでに削除してある
・何度かやり直してるので画像に表示されているプロジェクトIDが統一されていない
:::

![スクリーンショット 2023-03-27 18.05.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165688/820eafff-bb6c-0901-10da-c6a5810fad26.png)
プロジェクトの作成をクリック

![スクリーンショット 2023-03-27 18.06.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165688/6d389dbb-2cf2-f348-4b02-59286748d66a.png)
プロジェクト名を入力してチェックボックスにチェックを入れる

:::note info
プロジェクト名の下にある`fir-test-f5437`がプロジェクトIDになる
:::

![スクリーンショット 2023-03-27 18.07.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165688/a2a005fc-aeac-2ef7-e2ff-05a56067b39a.png)
Googleアナリティクスは必要ならそのまま不要なら無効にする
※ 今回は使わないので無効で作成してます

![スクリーンショット 2023-03-27 18.07.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165688/944706a4-7e1a-007b-4f22-aae9468c2c75.png)
一通り終わったらこの画面になりプロジェクトの作成は完了

# Firestore Databaseの準備

:::note info
ローカルに開発環境を構築するときに準備が終わっていないとエラーになるので準備しておく
:::


![スクリーンショット 2023-03-28 15.53.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165688/9ad59a89-4987-b54b-4978-c68349ed3cd3.png)
Firebaseのコンソール画面の左のメニューの`構築 > Firestore Database`を選択

![スクリーンショット 2023-03-28 15.55.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165688/1b70dab3-fa67-8782-656c-18221a3f9bb9.png)
`データベースの作成`を選択

![スクリーンショット 2023-03-28 16.17.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165688/bbdc6abc-3574-e835-4c22-28d3fa5d541a.png)
セキュリティルールは`テストモード`で開始

:::note info
テストモードの有効期限が30日
:::

![スクリーンショット 2023-03-28 16.17.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165688/5eb0e504-bdbd-3129-dfca-9253f1128b8b.png)
ローケーションの設定は日本でしか使わないので`asia-norheast1(Tokyo)`を指定

# デフォルトのロケーションの設定

![スクリーンショット 2023-03-28 18.47.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165688/b8883a85-a8d8-928c-c9ee-a7a7d2401e7e.png)
左のメニューの`プロジェクトの概要`の横にある歯車をクリップして出てくる`プロジェクトの設定`を選択

![スクリーンショット 2023-03-28 18.47.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165688/cc2ae53f-b7bb-0263-ffc5-6639425f3502.png)
`デフォルトの GCP リソース ロケーション`を選択

![スクリーンショット 2023-03-28 18.54.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165688/dba5061b-f773-e795-57cc-384f8afcaebd.png)
Firestore Databaseで`asia-norheast1(Tokyo)`を選択したので自動で設定されてからそのまま完了

これで準備は完了

# ローカル開発環境の構築

:::note alert
ローカルの開発環境はすべての機能を100%エミュレートするものではない
・Firestore Databaseのindexの動作確認ができない
:::

## firebaseコマンドのインストール
URL: https://firebase.google.com/docs/cli?hl=ja#mac-linux-auto-script

```bash
$ curl -sL https://firebase.tools | bash
```

## プロジェクトの初期化

プロジェクトのディレクトリを作成しそこに移動しておく

```bash
$ firebase init

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

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

  /Users/kashiwabarak/workspace/script/sandbox/firebase_install

? Which Firebase features do you want to set up for this directory? Press Space to select features, then Enter to confirm your choices. (Press <space> to select, <a> to toggle all, <i> to invert se
lection, and <enter> to proceed)
❯◯ Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance
 ◯ Firestore: Configure security rules and indexes files for Firestore
 ◯ Functions: Configure a Cloud Functions directory and its files
 ◯ Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys
 ◯ Hosting: Set up GitHub Action deploys
 ◯ Storage: Configure a security rules file for Cloud Storage
 ◯ Emulators: Set up local emulators for Firebase products
(Move up and down to reveal more choices)
```
up downのキーで使用したいエミュレータをspaceキーで選択

```bash
❯◉ Firestore: Configure security rules and indexes files for Firestore
 ◉ Functions: Configure a Cloud Functions directory and its files
```
今回はFirestoreとFunctionsを使うのでこの2つを選択

```bash:アカウント設定
=== Account Setup

Which account do you want to use for this project? Choose an account or add a new one now

? Please select an option: (Use arrow keys)
❯ hogehoge@gmail.com
  (add a new account)
```
すでにログイン済みの場合は選択欄に出てくるので選択

ログインしていない場合は`(add a new account)`を選択してログイン
この場合はブラウザが開いて表示されてる手順通りに進めばログインできます

```bash:プロジェクトの設定
=== 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 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
```
プロジェクトを作成しているので`Use an existing project`を選択


```bash
? Please select an option: Use an existing project
? Select a default Firebase project for this directory: (Use arrow keys)
❯ [プロジェクトID] ([プロジェクト名])
```
作成済みのプロジェクト一覧が表示されるので先程作成したものを選択

```bash
=== Firestore Setup

Firestore Security Rules allow you to define how and when to allow
requests. You can keep these rules in your project directory
and publish them with firebase deploy.

? What file should be used for Firestore Rules? (firestore.rules)
```
Firestoreのセキュリティルールのファイルをどうするのか聞かれるけど特に変更する必要がなければデフォルトのまま
デフォルトは`firestore.rules`になる

```bash
Firestore indexes allow you to perform complex queries while
maintaining performance that scales with the size of the result
set. You can keep index definitions in your project directory
and publish them with firebase deploy.

? What file should be used for Firestore indexes? (firestore.indexes.json)
```
Firestoreのインデックスを設定するファイルを聞かれるのでこれもデフォルトのまま
デフォルトは`firestore.indexes.json`になる

```bash
=== Functions Setup
Let's create a new codebase for your functions.
A directory corresponding to the codebase will be created in your project
with sample code pre-configured.

See https://firebase.google.com/docs/functions/organize-functions for
more information on organizing your functions using codebases.

Functions can be deployed with firebase deploy.

? What language would you like to use to write Cloud Functions? (Use arrow keys)
❯ JavaScript
  TypeScript
```
Functionsで使用する言語を聞かれるので好きな方を選択
`JavaScript`を選択してます

```bash
? Do you want to use ESLint to catch probable bugs and enforce style? (y/N)
```
ESLintを使用するかどうかを聞かれるので好きな方を選択
`y`を選択してます

```bash
? Do you want to install dependencies with npm now? (Y/n)
```
npmの依存関係のインストールは無難に`Y`を選択

```bash
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: undefined,
npm WARN EBADENGINE   required: { node: '16' },
npm WARN EBADENGINE   current: { node: 'v19.6.1', npm: '9.4.0' }
npm WARN EBADENGINE }

added 316 packages, and audited 317 packages in 10s

35 packages are looking for funding
  run `npm fund` for details

2 moderate severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.
npm notice
npm notice New minor version of npm available! 9.4.0 -> 9.6.2
npm notice Changelog: https://github.com/npm/cli/releases/tag/v9.6.2
npm notice Run npm install -g npm@9.6.2 to update!
npm notice

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

✔  Firebase initialization complete!
```
初期化完了

```bash
$ ls -la
total 40
-rw-r--r--  1 user  0000000    56  3 29 10:21 .firebaserc
-rw-r--r--  1 user  0000000  1166  3 29 10:21 .gitignore
-rw-r--r--  1 user  0000000   396  3 29 10:21 firebase.json
-rw-r--r--  1 user  0000000    44  3 29 10:11 firestore.indexes.json
-rw-r--r--  1 user  0000000   712  3 29 10:09 firestore.rules
drwxr-xr-x  8 user  0000000   256  3 29 10:21 functions

$ ls -la ./functions/
total 280
-rw-r--r--    1 user  0000000     188  3 29 10:19 .eslintrc.js
-rw-r--r--    1 user  0000000      13  3 29 10:19 .gitignore
-rw-r--r--    1 user  0000000     352  3 29 10:19 index.js
drwxr-xr-x  261 user  0000000    8352  3 29 10:21 node_modules
-rw-r--r--    1 user  0000000  125832  3 29 10:21 package-lock.json
-rw-r--r--    1 user  0000000     638  3 29 10:19 package.json
```
作成されたものを見てみるとこんな感じ

# エミュレータの起動

```bash:起動コマンド
$ firebase emulators:start
```

```bash:起動
i  emulators: Starting emulators: functions, firestore
⚠  functions: The following emulators are not running, calls to these services from the Functions emulator will affect production: auth, database, hosting, pubsub, storage
⚠  Your requested "node" version "16" doesn't match your global version "19". Using node@19 from host.
i  firestore: Firestore Emulator logging to firestore-debug.log
✔  firestore: Firestore Emulator UI websocket is running on 9150.
i  ui: Emulator UI logging to ui-debug.log
i  functions: Watching "/Users/kashiwabarak/workspace/script/sandbox/firebase_install/functions" for Cloud Functions...
⚠  functions: package.json indicates an outdated version of firebase-functions. Please upgrade using npm install --save firebase-functions@latest in your functions directory.
⚠  functions: Please note that there will be breaking changes when you upgrade.
✔  functions: Loaded functions definitions from source: .

┌─────────────────────────────────────────────────────────────┐
│ ✔  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             │
├───────────┼────────────────┼─────────────────────────────────┤
│ Functions │ 127.0.0.1:5001 │ http://127.0.0.1:4000/functions │
├───────────┼────────────────┼─────────────────────────────────┤
│ 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, 9150

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

エミュレータUIのURL `http://127.0.0.1:4000/`にアクセスしてこんな感じの画面が表示されれば成功
![スクリーンショット 2023-03-29 10.33.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165688/09fb57d5-bb22-972f-5abb-f07a9f91666e.png)

## Functionsを使用してみる

初期化で作成されたFunctionsのファイルを編集してコメントアウトを外してこんな感じにする
```javascript:functions/index.js
const functions = require("firebase-functions");

// Create and deploy your first functions
// https://firebase.google.com/docs/functions/get-started

exports.helloWorld = functions.https.onRequest((request, response) => {
  functions.logger.info("Hello logs!", {structuredData: true});
  response.send("Hello from Firebase!");
});
```

エミュレータを動かしている画面でこんな感じの表示がされ先程コメントアウトを外した`helloWorld`のURLが表示される
```bash
⚠  functions: package.json indicates an outdated version of firebase-functions. Please upgrade using npm install --save firebase-functions@latest in your functions directory.
⚠  functions: Please note that there will be breaking changes when you upgrade.
✔  functions: Loaded functions definitions from source: helloWorld.
✔  functions[us-central1-helloWorld]: http function initialized (http://127.0.0.1:5001/fir-test-d0d07/us-central1/helloWorld).
```

URLにアクセスして`Hello from Firebase!`と表示されば成功

# デプロイ

:::note info
デプロイするには従量課金制のプランにする必要です
:::

```bash:使用するプロジェクトIDを設定
$ firebase use [プロジェクトID]
```

```bash:デプロイ
$ firebase deploy
```

```bash:functionsのみデプロイ
$ firebase deploy --only functions[:function名]
```


# ハマったところ

## firebase initでエラー

```bash:エラー内容
=== Firestore Setup

Error: It looks like you haven't used Cloud Firestore in this project before. Go to https://console.firebase.google.com/project/[プロジェクトID]/firestore to create your Cloud Firestore database.
```

Firestore作成済みなのに作ってと言われました
プロジェクトの設定のデフォルトのロケーションの設定を行ったら表示されなくなった

憶測ですがデフォルトが`nam5 (us-central)`だったので
この設定がない場合`nam5 (us-central)`にFirestoreが作成されているかどうかの確認をしてるのではないかと