Firebaseの開発環境（local）を作ってみるよ

## 経緯
・firebase-toolsのバージョンが上がってCloud StorageのEmulatorが実装されたみたい
・Node.jsバージョン16がCloudFunctionsでサポートされたみたい

## 必要なもの、必要な知識
・Firebaseとは何か勉強しておいて
・Terminal操作ができるようにしておいて（コマンドコピペできる程度で）
・Homebrew インストールしておいて
・Googleアカウントは作っておいて
・GitHubのアカウントは作っておいて
・Node.jsはインストールしておいて（記事内ではVer.16+でやるよ）
・エディタはVisual Studio Code使うよ
・Gitは使うからインストールしといて

## 環境とか
・MacBookPro '13 (2017) BigSur
・Homebrew 3.2.11
・Visual Studio Code 1.16.0
・Node.js 16.9.1

## 事前に作成しておくと良いこと
・Googleのアカウント作成とfirebaseのプロジェクト作成、firestoreの作成
・GitHubのアカウントと作ったプロジェクトをcommitするようのリポジトリ
　※privateリポジトリにしておいたほうが良いかも。


## Let's Try!!!

### 作業用ディレクトリの作成・移動
```
$ mkdir ~/Documents/Sample/firebase-local
$ cd ~/Documents/Sample/firebase-local
```

### git初期化（いつものやつね）
```
$ git init
```

### .gitignore作成（自動生成させちゃうよ）
giboがインストールされてない場合は、```brew install gibo```
オプションは```macos```だけでよさそうだけど、まとめて全部ガツンと行っちゃえ！

```
$ gibo dump macos linux windows node > .gitignore
```

### （念の為）ちゃんと出来てるか確認しておこう
```
$ ls -a
.         ..        .git      .gitignor
```
よさげね。

### （ここで？）Node.jsとnpmのバージョン確認しておこうか( ･`ω･´)
```
$ node -v
v16.9.1
$ npm -v
7.21.1
```

### FirebaseCLIが必要だからインストールするんだぜ
```
$ npm install -g firebase-tools
```

### firebaseのバージョンを確認しておこう！
```
$ firebase --version
9.18.0
```
### firebaseにログインする
```
$ firebase login
```
ブラウザが自動的に開いてログイン。
流れに沿ってfirebaseCLIへのアクセス許可をする。
![スクリーンショット 2021-09-13 23.25.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82089/f8a63879-da3d-8b16-1cd5-e8e6fa7e4c1a.png)

Firebase CLI Login Successful
が表示されるとOK!（画面は閉じてOK）

### Firebase Consoleにログインしてプロジェクトを作成！
![スクリーンショット 2021-09-13 23.35.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82089/2e39c01e-a3e3-38b2-8a08-626581a93de6.png)

![スクリーンショット 2021-09-13 23.08.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82089/ce167920-c080-6798-f806-e4515c0800bf.png)

![スクリーンショット 2021-09-13 23.08.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82089/03e402b6-88a3-8358-f712-82a9c11ee351.png)
アナリティクスはOFFに

![スクリーンショット 2021-09-13 23.35.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82089/a809c5fa-74f7-9798-9823-e8fc5dc42fc0.png)

完成！


### firebaseのプロジェクトディレクトリとして初期化するよ
ココからはTerminalに戻って作業続行するよ

```
$ firebase init

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

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

  /Users/UserName/Documents/Sample/firebase-local

? 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 selection)
❯◯ 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)
```

せっかくなので、全部チェック入れちゃえ！
↑↓で移動して＜space＞キーでチェックを入れるんだ！
選択後。。。

```
 ◉ 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
```

今回は新規プロジェクトとして作成```Create a new project```を選択して ＜Enter＞

```
? Which Firebase features do you want to set up for this directory? Press Space to select features, then Enter to confirm your choices. Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision de
fault 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 deplo
ys, Hosting: Set up GitHub Action deploys, Storage: Configure a security rules file for Cloud Storage, Emulators: Set up local emulators for Firebase products, Remote Config: Configure a template file for Remote Config

=== 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
　 Create a new project
  Add Firebase to an existing Google Cloud Platform project
  Don't set up a default project
```

```Use an existing project```を選択して＜Enter＞

```
? Select a default Firebase project for this directory: (Use arrow keys)
❯ fb-tool-sample (fb-tool-sample)
```

先程画面から作成した```fb-tool-sample```を選択して＜Enter＞

```
=== Database Setup
i  database: ensuring required API firebasedatabase.googleapis.com is enabled...
⚠  database: missing required API firebasedatabase.googleapis.com. Enabling now...
✔  database: required API firebasedatabase.googleapis.com is enabled

? It seems like you haven’t initialized Realtime Database in your project yet. Do you want to set it up? Yes　←　"Y" で回答
? Please choose the location for your default Realtime Database instance: asia-southeast1　←　"asia-southeast1"を選択
✔ Creating your default Realtime Database instance: fb-tool-sample-default-rtdb

Firebase Realtime Database Security Rules allow you to define how your data should be
structured and when your data can be read from and written to.

? What file should be used for Realtime Database Security Rules? database.rules.json ← デフォルトのまま＜Enter＞
✔  Database Rules for fb-tool-sample-default-rtdb have been written to database.rules.json.
Future modifications to database.rules.json will update Realtime Database Security Rules when you run
firebase deploy.

=== Firestore Setup

Error: It looks like you haven't used Cloud Firestore in this project before. Go to https://console.firebase.google.com/project/fb-tool-sample/firestore to create your Cloud Firestore database.
```

あれ？エラーなった。。。
なに？なに？
要約すると```あなたはFirestore使ったことがないみたいだから、URL踏んで作ってきて```的な感じ。
言われたとおり、画面にログインしてプロジェクトを選択後、firestoreのデータベースを作成する。
画面キャプチャは省略〜```テストモード```で```asia-noatheast3```で作ってみた。

```
firebase init

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

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

  /Users/UserName/Documents/Sample/firebase-local

? Which Firebase features do you want to set up for this directory? Press Space to select features, then Enter to confirm your choices. Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision de
fault 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 deplo
ys, Hosting: Set up GitHub Action deploys, Storage: Configure a security rules file for Cloud Storage, Emulators: Set up local emulators for Firebase products, Remote Config: Configure a template file for Remote Config

=== 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: fb-tool-sample (fb-tool-sample)
i  Using project fb-tool-sample (fb-tool-sample)

=== Database Setup
i  database: ensuring required API firebasedatabase.googleapis.com is enabled...
✔  database: required API firebasedatabase.googleapis.com is enabled


Firebase Realtime Database Security Rules allow you to define how your data should be
structured and when your data can be read from and written to.

? What file should be used for Realtime Database Security Rules? database.rules.json
? File database.rules.json already exists. Do you want to overwrite it with the Realtime Database Security Rules for fb-tool-sample-default-rtdb from the Firebase console? No
Skipping overwrite of Realtime Database Security Rules.
The security rules defined in database.rules.json will be published when you run firebase deploy.

=== 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
? File firestore.rules already exists. Do you want to overwrite it with the Firestore Rules from the Firebase Console? No

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
? File firestore.indexes.json already exists. Do you want to overwrite it with the Firestore Indexes from the Firebase Console? No

=== Functions Setup

A functions directory will be created in your project with sample code
pre-configured. Functions can be deployed with firebase deploy.

? What language would you like to use to write Cloud Functions? JavaScript
? Do you want to use ESLint to catch probable bugs and enforce style? No
? File functions/package.json already exists. Overwrite? No
i  Skipping write of functions/package.json
? File functions/index.js already exists. Overwrite? No
i  Skipping write of functions/index.js
? File functions/.gitignore already exists. Overwrite? No
i  Skipping write of functions/.gitignore
? Do you want to install dependencies with npm now? Yes
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: undefined,
npm WARN EBADENGINE   required: { node: '14' },
npm WARN EBADENGINE   current: { node: 'v16.9.1', npm: '7.21.1' }
npm WARN EBADENGINE }

up to date, audited 323 packages in 3s

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

found 0 vulnerabilities

=== Hosting Setup

Your public directory is the folder (relative to your project directory) that
will contain Hosting assets to be uploaded with firebase deploy. If you
have a build process for your assets, use your build's output directory.

? What do you want to use as your public directory? public
? Configure as a single-page app (rewrite all urls to /index.html)? No
? Set up automatic builds and deploys with GitHub? No
✔  Wrote public/404.html
? File public/index.html already exists. Overwrite? No
i  Skipping write of public/index.html

=== Hosting:github Setup

i  Detected a .git folder at /Users/UserName/Documents/Sample/firebase-local
i  Authorizing with GitHub to upload your service account to a GitHub repository's secrets store.

Visit this URL on this device to log in:
https://github.com/login/oauth/authorize?client_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxx&state=xxxxxxxxxxxxxxx&redirect_uri=http%3A%2F%2Flocalhost%3A9005&scope=read%3Auser%20repo%20public_repo

Waiting for authentication...

✔  Success! Logged into GitHub as UserName

? For which GitHub repository would you like to set up a GitHub workflow? (format: user/repository) UserName/fb-tool-sample

✔  Created service account github-action-406020156 with Firebase Hosting admin permissions.
✔  Uploaded service account JSON to GitHub as secret FIREBASE_SERVICE_ACCOUNT_FB_TOOL_SAMPLE.
i  You can manage your secrets at https://github.com/UserName/fb-tool-sample/settings/secrets.

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

✔  Created workflow file /Users/UserName/Documents/Sample/firebase-local/.github/workflows/firebase-hosting-pull-request.yml
? Set up automatic deployment to your site's live channel when a PR is merged? Yes
? What is the name of the GitHub branch associated with your site's live channel? main

✔  Created workflow file /Users/UserName/Documents/Sample/firebase-local/.github/workflows/firebase-hosting-merge.yml

i  Action required: Visit this URL to revoke authorization for the Firebase CLI GitHub OAuth App:
https://github.com/settings/connections/applications/89cf50f02ac6aaed3484
i  Action required: Push any new workflow file(s) to your repo

=== Storage Setup

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

? What file should be used for Storage Rules? storage.rules
✔  Wrote storage.rules

=== Emulators Setup
? Which Firebase emulators do you want to set up? Press Space to select emulators, then Enter to confirm your choices. Authentication Emulator, Functions Emulator, Firestore Emulator, Database Emulator, Hosting Emulator, Pub/Sub Emulator,
 Storage Emulator
? Which port do you want to use for the auth emulator? 9099
? Which port do you want to use for the functions emulator? 5001
? Which port do you want to use for the firestore emulator? 8080
? Which port do you want to use for the database emulator? 9000
? Which port do you want to use for the hosting emulator? 5000
? Which port do you want to use for the pubsub emulator? 8085
? Which port do you want to use for the storage emulator? 9199
? Would you like to enable the Emulator UI? Yes
? Which port do you want to use for the Emulator UI (leave empty to use any available port)?
? Would you like to download the emulators now? No

=== Remoteconfig Setup
? What file should be used for your Remote Config template? remoteconfig.template.json

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

✔  Firebase initialization complete!
```

## Emulatorの初期化（インストール）
エミュレータは全部選択。
ポートは全部デフォルト。

```
$ firebase init emulators

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

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

  /Users/UserName/Documents/Sample/firebase-local

Before we get started, keep in mind:

  * You are initializing within an existing Firebase project directory


=== 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.

i  .firebaserc already has a default project, using fb-tool-sample.

=== Emulators Setup
? Which Firebase emulators do you want to set up? Press Space to select emulators, then Enter to confirm your choices. (Press <space> to select, <a> to toggle all, <i> to invert selection)Authentication Emulator, Functions Emulator, Firestore Emulator, Database Emulator, Hosting Emulator, Pub/Sub Emulator, Storage Emulator
i  Port for auth already configured: 9099
i  Port for functions already configured: 5001
i  Port for firestore already configured: 8080
i  Port for database already configured: 9000
i  Port for hosting already configured: 5000
i  Port for pubsub already configured: 8085
i  Port for storage already configured: 9199
i  Emulator UI already enabled with port: (automatic)
? Would you like to download the emulators now? No

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

✔  Firebase initialization complete!
```


## エミュレータ起動じゃぁ！
```
$ firebase emulators:start

i  emulators: Starting emulators: auth, functions, firestore, database, hosting, pubsub, storage
⚠  Your requested "node" version "14" doesn't match your global version "16"
i  firestore: downloading cloud-firestore-emulator-v1.13.1.jar...
Progress: =====================================> (100% of 61MB)
i  firestore: Removing outdated emulator files: cloud-firestore-emulator-v1.11.15.jar
i  firestore: Firestore Emulator logging to firestore-debug.log
i  emulators: Shutting down emulators.
i  functions: Stopping Functions Emulator
i  firestore: Stopping Firestore Emulator
i  hub: Stopping emulator hub
⚠  database: Port 9000 is not open on localhost, could not start Database Emulator.
⚠  database: To select a different host/port, specify that host/port in a firebase.json config file:
      {
        // ...
        "emulators": {
          "database": {
            "host": "HOST",
            "port": "PORT"
          }
        }
      }
i  emulators: Shutting down emulators.

Error: Could not start Database Emulator, port taken.
```
あ。。。エラーです。
一旦、firebase.jsonを確認する

```
cat firebase.json

{
  "functions": {
    "source": "functions"
  },
  "database": {
    "rules": "database.rules.json"
  },
  "firestore": {
    "rules": "firestore.rules",
    "indexes": "firestore.indexes.json"
  },
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ]
  },
  "storage": {
    "rules": "storage.rules"
  },
  "emulators": {
    "auth": {
      "port": 9099
    },
    "functions": {
      "port": 5001
    },
    "firestore": {
      "port": 8080
    },
    "database": {
      "port": 9000
    },
    "hosting": {
      "port": 5000
    },
    "pubsub": {
      "port": 8085
    },
    "storage": {
      "port": 9199
    },
    "ui": {
      "enabled": true
    }
  },
  "remoteconfig": {
    "template": "remoteconfig.template.json"
  }
}
```

ホストの指定が足りないの？ポートがBusyなの？
ポートから当たってみますか。。。

```
$ lsof -i :9000
COMMAND   PID    USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
php-fpm 67668 UserName    8u  IPv4 0x615724fb70f47db1      0t0  TCP localhost:cslistener (LISTEN)
php-fpm 67669 UserName    9u  IPv4 0x615724fb70f47db1      0t0  TCP localhost:cslistener (LISTEN)
php-fpm 67670 UserName    9u  IPv4 0x615724fb70f47db1      0t0  TCP localhost:cslistener (LISTEN)
```

やっぱり。。。ごめんなさい。ごめんなさい。ごめんなさいぃぃぃぃ。
じゃあ、別ポート使えばいいじゃん！

念の為、ポートが使われてないことを確認。

```
$ lsof -i :9001
````
結果が標準出力が何もなければ使われてない。
でもって、```firebase.config```を修正する。
もう、抜粋でいいよね。

```
    "database": {
      "port": 9001
    },
```

これで完璧のはずだ！

```
$ firebase emulators:start
i  emulators: Starting emulators: auth, functions, firestore, database, hosting, pubsub, storage
⚠  Your requested "node" version "14" doesn't match your global version "16"
i  firestore: Firestore Emulator logging to firestore-debug.log
i  database: Database Emulator logging to database-debug.log
i  pubsub: Pub/Sub Emulator logging to pubsub-debug.log
i  hosting: Serving hosting files from: public
✔  hosting: Local server: http://localhost:5000
i  ui: Emulator UI logging to ui-debug.log
i  functions: Watching "/Users/UserName/Documents/Sample/firebase-local/functions" for Cloud Functions...

┌─────────────────────────────────────────────────────────────┐
│ ✔  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      │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Functions      │ localhost:5001 │ http://localhost:4000/functions │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Firestore      │ localhost:8080 │ http://localhost:4000/firestore │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Database       │ localhost:9001 │ http://localhost:4000/database  │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Hosting        │ localhost:5000 │ n/a                             │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Pub/Sub        │ localhost:8085 │ 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.

```

ちゃんと起動した？？？？？

### エミュレータの起動確認
ブラウザから、```http://localhost:4000/```にアクセスする。

![スクリーンショット 2021-09-14 10.30.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82089/50b1bce1-853f-4224-baec-31eea007c82f.png)


全部起動してる！
終了するときは、Terminalで```Ctrl + c```で終了します。

## まとめ。所感とか。
最初から環境構築をする手順をまとめとくと良かったといつも思う。
今回は、その反省も踏まえてまとめてみた。
失敗したことやエラーになったこともちゃんと残しておくのは大事だと思う。

```firebase init```実行時の選択オプションなんかは、詳しく書かなかった（メンドウダッタ）
使いたい環境によって読み替えて設定すればいいと思う。```TypeScript/JavaScript```の選択は好みや要件が絡むところだろうから。
基本的には、デフォルトで＜Enter＞バンバン叩いて勧めていけば問題ない感じだった。

試行錯誤しながらハンズオンでやってみたから、手順が変なところとかあるかもしれないので、指摘があれば修正していきたいと思います。

LGTM10件来たら続編でも書こうかな。

## 参考
[Local Emulator Suite のインストール、構成、統合](https://firebase.google.com/docs/emulator-suite/install_and_configure?hl=ja)
[Firebase CLI リファレンス](https://firebase.google.com/docs/cli?hl=ja)

## 改訂履歴
2021.09.14 初版