FirebaseをTypeScriptで入門する on May, 2019

`Firebase 入門` とか `React 入門` とかいろいろググっても「Firebaseとは〜mBaaSで〜」「Reactとは〜JSXで〜」みたいなゆるふわな概念しかなかったので、備忘録としてまとめました。

Reactのほうは[こっち](https://qiita.com/awa2/items/d83a5a614bf99994bbd8)。

# 環境づくり
## node
最初に環境作ったときは、下記のnoteが出ました。
`Please update to Node >=8.10 and npm >=5 to get supported tools in new projects.`
予めアップデートしておいたほうが良さそうです。

今回は、node 8.11 とnpm 6.9でやりました。nodenv使うと便利です。

## firebaseプロジェクト
コンソールから作成して下さい。
https://console.firebase.google.com/u/0/?hl=ja

データベースには、

 * Realtime Database
    * リアルタイムな巨大なJSON（ざっくり）
 * cloud Firestore
    * RealtimeDatabaseより新しく強力なNoSQL

の二種類があります。`Database`から使う方を有効にしておきます。

## その他のツールのグローバルインストール
```bash
$ npm install -g firebase-tools
$ npm install -g create-react-app
$ npm install -g typescript
```
 * Firebase Tools
    * Firebaseへデプロイするツール
 * Create React App
    * Reactの開発環境を一発で作ってくれるツール
    * 実際にはBableやらWebpackやら必要だが、よしなにしてくれる
 * TypeScript
    * TypeScriptのトランスパイラ

# プロジェクトを作る
## React + Firebase
いろんな方法がありそうだけど、以下の感じでやりました。

```bash
$ create-react-app your-app --typescript
```
今はこの`--typescript`オプションを使うのが正しいようです。

`your-app`フォルダが作成されて、いろいろダウンロードされます。結構時間がかかります。

次は、firebaseです。

```bash
$ cd your-app
$ firebase init
```
FirebaseToolsの対話型ウィザードが始まりますので、

```
? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices.
 * Database: Deploy Firebase Realtime Database Rules,
 * Firestore: Deploy rules and create indexes for Firestore,
 * Functions: Configure and deploy Cloud Functions, 
 * Hosting: Configure and deploy Firebase Hosting sites, 
 * Storage: Deploy Cloud Storage security rules
```
とりあえず全部いじりたいので、全部選択（スペースキーを押下）して、Enterし、

```
? Select a default Firebase project for this directory: <YOUR_FIREBASE_PJ>
? What file should be used for Database Rules? database.rules.json
? What file should be used for Firestore Rules? firestore.rules
? What file should be used for Firestore indexes? firestore.indexes.json
? What language would you like to use to write Cloud Functions? TypeScript
? Do you want to use TSLint to catch probable bugs and enforce style? Yes
? Do you want to install dependencies with npm now? Yes
? What do you want to use as your public directory? public
? Configure as a single-page app (rewrite all urls to /index.html)? No
? File public/index.html already exists. Overwrite? No
? What file should be used for Storage Rules? storage.rules
✔  Firebase initialization complete!
```
とそれぞれ答えます。ここはお好みですね。
(上記はダイアログだけ抜粋しています）

## アプリ開発準備
firebaseいれます。

```bash
$ npm install -S firebase
```

firebase.jsonを変更して、hostingのデプロイ先を`public`フォルダから`build`フォルダに変更します。

```json:firebase.json
{
  "database": {
    "rules": "database.rules.json"
  },
  "firestore": {
    "rules": "firestore.rules",
    "indexes": "firestore.indexes.json"
  },
  "functions": {
    "predeploy": [
      "npm --prefix \"$RESOURCE_DIR\" run lint",
      "npm --prefix \"$RESOURCE_DIR\" run build"
    ]
  },
  "hosting": {
    "public": "build",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ]
  },
  "storage": {
    "rules": "storage.rules"
  }
}
```

さらに、ReactのTypeScript定義ファイルを入れます。入れないとトランスパイル時に「は？このimportしたreactって何？もう知らないからね！anyにしちゃうからね！」って怒られます。

```bash
$npm install -D @types/react
```


## 初回ビルド＆初回デプロイ

```bash
$yarn build
```
`$npm run build`でもいいです。
成功すると、`build`フォルダ下にデプロイするべきファイルが出来上がっています。

このままデプロイできるのですが、今の状態だと`functions/src`の下のTypeScriptが「firebase-functionsインポートしてるくせに使ってないやん！」みたいなトランスパイルエラーになってデプロイが止まりますので

```functions/src/index.ts
import * as functions from 'firebase-functions';

// Start writing Firebase Functions
// https://firebase.google.com/docs/functions/typescript

export const helloWorld = functions.https.onRequest((request, response) => {
 response.send("Hello from Firebase!");
});
```

とコメントアウトして簡単な関数を定義しておくと良いです。

```bash
$ firebase deploy
```

これでデプロイです。

デプロイしたら、コンソール上で、Hostingやfunctionsがデプロイされていることを確認しましょう。

functionsはデフォルトでは、`us-central1`リージョンにnodejs8ラインタイムでデプロイされるようです。必要があれば、コード上からregionを変更できます、`asia-northeast1`（東京）も選べます。

 * **[Cloud Functions のロケーション | Firebase](https://firebase.google.com/docs/functions/locations?hl=ja)**

## デプロイ色々

```bash
# hostingだけ
$ firebase deploy --only hosting
# functionsだけ
$ firebase deploy --only functions
# 他にもdatabase、storage、firestoreがオプションで選べる。
# これらの名前は、firebase.json 構成ファイル内のキーに対応している。
```

# 開発する
## Firebase SDKをフロントエンドに入れる
Firebaseのプロジェクト設定から「全般」->「アプリ」を選んで、Webアプリを追加して下さい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247444/d6d4196b-0056-c064-8169-bc877605ce83.png)

Firebase SDKをHTMLに埋め込む手段として、従来は、こんなのを入れる必要がありました。

```JavaScript
const config = {
  apiKey: 'xxxxx',
  authDomain: 'xxxxx.firebaseapp.com',
  databaseURL: 'https://xxxxx.firebaseio.com',
  projectId: 'xxxxx',
  storageBucket: '',
  messagingSenderId: 'xxxxx'
}
```

現在は、さらによしなにしてくれていて、上記画像の「自動」に表示されているスニペットを入れればOKです。
なお、従来のやり方であるconfigのスニペットも上記画像の「構成」を選べば表示されます。ただ、デプロイ先を開発、ステージング、本番といった分け方をする場合には、この「自動」を使っておいたほうが良さそうです。

今回入れるスニペット

```HTML
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="/__/firebase/6.0.2/firebase-app.js"></script>

<!-- TODO: Add SDKs for Firebase products that you want to use
     https://firebase.google.com/docs/web/setup#reserved-urls -->

<!-- Initialize Firebase -->
<script src="/__/firebase/init.js"></script>
```

## SDKの初期化

先程いれた`/__/firebase/init.js`が初期化用のjsonを生成してくれます。

```JavaScript
fetch('/__/firebase/init.json').then(response => {
  firebase.initializeApp(response.json());
});
```

これで取得できます。非同期なので、ちょっと取り回しは悪いですが、環境ごとにconfigをわけなくて良いですね。

次はReactです。

# 参考文献
[React + Redux + Firebaseで作るTodo App](https://qiita.com/gonta616/items/278a7e81a8b624d9621e)