Circle CIからFirebase Hostingに自動ビルド&デプロイする

# 前書き
Firebaseが東京リージョン来たしSPAのホスティングもNetlifyから丸ごと移そうと思いたったのですが、
NetlifyはGitHub連携でお手軽な一方Firebaseでは別途CIツールを使わないといけなく。。。
ビルドとデプロイはさすがに`git push`されたら自動でやってほしいしCircleCIに興味があったから試してみよう、
ということでやってみたほぼほぼ最低限の覚書です。


# この記事で書いていること
- SPAプロジェクトをfirebase-toolsを使いFirebase Hostingへデプロイする方法
- 上記をCircleCI上で自動化しビルド＆デプロイする方法


# この記事で書いていないこと
- Node.js/npmのインストール方法および使い方

- ビルド処理などの内容やコマンドの書き方
  記事中では`circleci-firebase`を既存jsプロジェクトとし、
  ビルドコマンドは`npm run build` 出力先は`circleci-firebase/dist`とします。

- Firebaseプロジェクトの作成方法や細かい設定
  記事中ではFirebaseコンソール上で事前に作成した`circleci-firebase`プロジェクトを使用しています。

- GitHub/CircleCIの登録方法および連携方法、および細かい設定
  記事中ではdevelopブランチを対象に自動化する手順となっています。


# 環境
### ローカル環境
  - Node.js 10.7.0
  - firebase-tools 6.4.0

### サービス
  - Firebase
  - GitHub
  - CircleCI


# firebase-toolsを使ってプロジェクトをFirebase Hostingへデプロイする
自動化の前に手動でFirebase Hostingにデプロイできるようにします。

### firebase-toolsのインストール
以下のコマンドを実行し、グローバルに`firebase-tools`をインストールします。

```sh
$ npm install -g firebase-tools
```


初回はログインが必要なので以下のコマンドを実行します。
実行後、ブラウザでFirebaseへのアクセス許可を求められます。

```sh
$ firebase login
```


### 作成したプロジェクトをfirebase-toolsで扱えるようにする
`circleci-firebase`直下で以下のコマンドを実行しコンソールに沿って設定します。

```sh
$ firebase init
```


```sh
## ディレクトリの確認
You're about to initialize a Firebase project in this directory:

  hoge\fuga\circleci-firebase

? Are you ready to proceed? (Y/n) Y
```


```sh
## スペースで対象とする機能を選択、今回はHostingのみ
? Which Firebase CLI features do you want to setup 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
```


```sh
## 紐づけるFirebaseプロジェクトの選択、create a new projectを選択
? Select a default Firebase project for this directory:
  [don't setup a default project]
  (Firebaseプロジェクトがあれば出てくる)
> [create a new project]
```


```sh
## デプロイ対象のディレクトリを指定する、今回はdist
? What do you want to use as your public directory? dist
```


```sh
## SPAかどうかを聞かれる、yを入力
? Configure as a single-page app (rewrite all urls to /index.html)? (y/N) y
```


```sh
## index.htmlが存在すればそれを上書きするかどうか聞かれる
## 筆者の環境では既存プロジェクトで既にあるのでNを入力
? File dist/index.html already exists. Overwrite? (y/N) N
```


ここまででfirebase-toolsでの初期化は完了です。
プロジェクト直下に`.firebaserc`と`firebase.json`ができます。

----

### Firebaseのプロジェクトを紐づける
続けて`circleci-firebase`直下で以下のコマンドを実行し、Firebaseプロジェクトを紐づけます。

```sh
$ firebase use --add
```


```sh
## デプロイする予定のFirebaseプロジェクトと紐づける
? Which project do you want to add? (Use arrow keys)
> circleci-firebase-xxxxx
  (他のプロジェクトなど)
```


```sh
## プロジェクトに端末上で扱うエイリアスを付ける
? What alias do you want to use for this project? (e.g. staging) circleci-firebase
```


確認のためビルド、デプロイします。
デプロイは`.firebaserc`などがある場所で`firebase deploy`を実行します。

```sh
## ビルド
$ npm run build

## デプロイ
$ firebase deploy

## 完了後、ホスティングされたURLが表示される
Hosting URL: https://circleci-firebase-xxxxx.firebaseapp.com
```


コマンドでFirebase Hostingへデプロイ出来るようになりました。
ここからはCircleCIで実行させるための手順です。

----

# CircleCIでプロジェクトをFirebase Hostingへビルド&デプロイする
### デプロイ用のFirebaseトークンを取得

```sh
$ firebase login:ci

Visit this URL on any device to log in:
(認証用のURL)

Waiting for authentication...

+  Success! Use this token to login on a CI server:

(トークンが表示されるので控える)

Example: firebase deploy --token "$FIREBASE_TOKEN"
```

### トークンをCircleCIへ登録
ここはCircleCIでの画面操作になります。
1.CircleCIにログイン後、画面のサイドバーから「JOBS」を選択し該当リポジトリの歯車アイコンをクリックして画面遷移
![circleci-1-1.png](https://qiita-image-store.s3.amazonaws.com/0/149610/81c4c946-00c6-5dc1-04d8-10ee7237e120.png)


2.BUILD SETTINGSの「Environment Variables」へ遷移
![circleci-2-2.png](https://qiita-image-store.s3.amazonaws.com/0/149610/b2cd4114-50eb-fe0d-14d6-85446562f4ab.png)


3.「Add Variable」から環境変数を登録
![circleci-3-3.png](https://qiita-image-store.s3.amazonaws.com/0/149610/1d3873d0-1be7-10b3-39f8-b4b8cbf7cbd5.png)
Nameには後々で使う変数名を入力、ここでは`FIREBASE_TOKEN`としました。
Valueには先ほど取得したFirebaseトークンを入力して「Add Variable」で登録します。


### firebase-toolsをプロジェクトにインストール
ローカルのコンソールに戻って以下を実行します。
CircleCIでは`npm -g`でのコマンド実行が出来ないため、firebase-toolsをプロジェクトにインストールします。

```sh
$ npm install --save-dev firebase-tools
```

### CircleCIの設定ファイルを作成
プロジェクト直下に`.circleci/config.yml`ファイルを作成します。
ポイントは先ほどCircleCIへ登録したトークン名`--token=$FIREBASE_TOKEN`を指定して認証しているところです。

```yml:config.yml
version: 2
jobs:
  deploy_dev: # ジョブ名
    docker:
      - image: circleci/node:10.7 # ジョブ実行環境のDockerイメージを記述
    steps:
      - checkout # ソースコードのチェックアウト
      - run: # 順に実行したいコマンドとコマンドに名前をつけます
          name: npm install
          command: npm i
      - run:
          name: build
          command: npm run build
      - run:
          name: deploy to Firebase Hosting
          command: ./node_modules/.bin/firebase deploy --token=$FIREBASE_TOKEN # プロジェクト上のfirebase-toolsでデプロイします

workflows:
  version: 2
  deploy_dev: # ワークフローの名前
    jobs:
      - deploy_dev: # 上で定義したジョブを指定します
          filters:
            branches:
              only: develop # developブランチのみを実行対象とします

```
ここまでで自動ビルド&デプロイの設定は完了です。
developブランチをビルド可能な状態でpushするとジョブが実行され、デプロイまで完了すると以下のようになります。
![4-1.png](https://qiita-image-store.s3.amazonaws.com/0/149610/b81d33c2-1235-f044-48c5-3d31766b74f5.png)

----

# まとめ
Netlifyのときもそうでしたがpushだけで自動的にジョブを走らせるのは楽になりました。
今回書いた方法は既存プロジェクトでも簡単に組み込めるかと思います。
Firebaseを利用しているなら実施コストよりもメリットがかなり大きいと思うのでぜひおすすめです。

ここまでお読みいただきありがとうございました。


# 参考リンク
[Firebase CLI リファレンス  |  Firebase](https://firebase.google.com/docs/cli/?hl=ja)
[Configuring Deploys - CircleCI](https://circleci.com/docs/2.0/deployment-integrations/#firebase)
[GitHubのプロジェクトをCircleCI 2.0でテストできるように移行してみる - jtwp470’s blog](https://jtwp470.hatenablog.jp/entry/2017/04/16/234609) (config.ymlの書き方の参考になりました)