Cloud Firestore を Vue CLI で動かしてみる

# はじめに
最近、Vue CLI を使えば、Cloud Firestore を動かすことが簡単にできることに気づいたので、
それを共有します
  
# 対象
* Firestore を試してみたいが、環境構築の方法がわからない方
* Firestore をとりあえず触ってみたい方

# ゴール
Vue CLI を使って、 Firestore へのデータの書き込み・読み出しを行うこと

# 環境

* Mac OS
* npm インストール済み

# Vue CLI のインストール ~ テストページの起動

## Vue CLI のインストール
```
$ npm install vue
$ npm install -g @vue/cli
```

## プロジェクトの作成・テストページの表示

プロジェクトを作成します
途中で設定をどうするか聞かれるので`default`を選択します

```
$ vue create my-project
```

Vue CLI を使ってテストページを開きます

```
$ cd my-project
$ npm run serve
```

ブラウザで http://localhost:8080/ をアクセスするとテストページが表示されます


![test-page.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/ffa655a6-7d8f-8a1c-daad-6da72a232230.png)


ここまでで、テストページの表示ができるようになりました

# Firebase の設定 ~ Vueに記載する設定の取得

Firebase コンソールにアクセスし、Firebaseプロジェクトを作成していきます(Google アカウントが必要)

コンソール

https://console.firebase.google.com/

## Firebase プロジェクトの作成
コンソール画面から、`プロジェクトを作成`を選択します
![コメント 2019-12-09 213927.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/7ed5db3d-f4b4-d564-c58d-e6ff0caa3a7b.png)

プロジェクト名を入力します
![コメント 2019-12-09 213452.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/6596ff66-ab2f-ccb5-8fab-b89140b3d81a.png)

注意点を確認し、「続行」
![コメント 2019-12-09 214309.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/581f2f41-5c38-6ad5-2298-414d2c4f1ab4.png)

そのままにして「続行」(off にしてもよいです)
![コメント 2019-12-09 214424.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/e9999fe8-5586-3ae9-61c6-866f9cf7b425.png)


「Default Account for Firebase」を選択します

![コメント 2019-12-09 214611.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/07e0560a-9bea-a393-57f4-214a47361630.png)

## Vueに記載する設定の取得

Vue で Firebase を利用するために必要な設定を取得します

`Project Overview` -> `</>` でWebアプリ設定画面へ

![コメント 2019-12-09 215319.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/5343558c-2b7d-0147-8fe2-da038eeac26a.png)

アプリ名を入力します
![コメント 2019-12-09 215609.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/4b971fd3-ecaa-7080-b1c2-1946fa917345.png)

以下の値をコピーしておきます

```
  // Your web app's Firebase configuration
  var firebaseConfig = {
    apiKey: [表示された値],
    authDomain: [表示された値],
    databaseURL: [表示された値]",
    projectId: [表示された値],
    storageBucket: [表示された値],
    messagingSenderId: [表示された値],
    appId: [表示された値],
    measurementId: [表示された値]
  };
  // Initialize Firebase
  firebase.initializeApp(firebaseConfig);
```

## Cloud Firestore の作成

1. メニューから Database を選択します
2. 「データベースを作成」を選択します
![コメント 2019-12-09 220229.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/ac7c0dca-6ae6-b5d6-f104-17b3ea6ad1f6.png)

3. 「テストモードで開始」を選択(**公開する時には、別途ルールの設定を行ってください**)
![コメント 2019-12-09 220455.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/b9778c2b-df89-4d6a-6476-8f2f8f03aa48.png)

4. `asia-northeast1(東京)`を選択します
![コメント 2019-12-09 220939.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/ac635e5d-bcdc-9e8c-8273-15710ae4408c.png)


以上で、Firebase 側の設定がおわります

# Vue で Firestore を利用する

## 初期化を行う
firebase パッケージをインストールします

```
$ npm install --save firebase
```

 `my-project/src/main.js` に、Cloud Firestore を初期化する処理を追加します

```js

// main.js
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

import firebase from 'firebase'
var firebaseConfig = {
  apiKey: [表示された値],
  authDomain: [表示された値],
  databaseURL: [表示された値],
  projectId: [表示された値],
  storageBucket: [表示された値],
  messagingSenderId: [表示された値],
  appId: [表示された値],
  measurementId: [表示された値]
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);

new Vue({
  render: h => h(App),
}).$mount('#app')

```

テストページをVue CLIで再度起動し、コンパイルエラーが発生していないことを確認します

```
$ cd [my-project へのパス]
$ npm run serve
```

以上で、Firestore を利用するための設定が終わりました

## データを追加する
Vuejs で、Firestore のコレクションに、データを追加してみます

### コーディング


以下のファイルを追加

* `src/components/todo/Add.vue`
* `src/App.vue`

```vuejs
// src/components/todo/Add.vue
<template>
  <div>
    <h1>New TODO</h1>
    <div>
      <ul>
        <li><input v-model="name"></li>
        <li><button v-on:click="addTodo">Add</button></li>
      </ul>
    </div>
  </div>
</template>

<script>
import firebase from 'firebase'
import 'firebase/firestore';

export default {
  name: 'todoAdd',
  data: function () {
    return {
      db: null,
      name: ''
    }
  },
  created: function() {
    this.db = firebase.firestore()
  },
  methods: {
    addTodo: function () {
      var _this = this

      // todos コレクションにドキュメントを追加
      this.db.collection('todos').add({
        name: _this.name
      })
      .then(function () {
        // 追加に成功したら、name を空にする
        _this.name = ''
      })
      .catch(function () {
        // エラー時の処理
      })
    }
  }
}
</script>


```

```vuejs

// src/App.vue
<template>
  <div id="app">
    <Add></Add>
  </div>
</template>

<script>
import Add from './components/todo/Add.vue'

export default {
  name: 'app',
  components: {
    Add
  }
}
</script>

```

### 動作確認
 
データが追加されることを確認するために、
Firebase Console の Database ページを開いておきます

![コメント 2019-12-09 222431.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/e09cfd71-a55e-5e69-6b1a-6565b3ab6d54.png)

`npm run serve` を実行し、http://localhost:8080/を開きます

![コメント 2019-12-09 230338.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/724f4798-9b7a-da49-e95b-ff612ccb3c32.png)


追加ボタンを押すと、
コンソール画面で、 `todos`コレクションが新たに作成され、その中にドキュメントが作成されていることがわかります
![コメント 2019-12-09 222431.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/e53d60a0-3d4d-417b-38a5-dadd510372f1.png)

## データを取得・監視する
Firestore では、コレクションやドキュメントの取得だけでなく、リアルタイムアップデートを取得することもできます
ここでは、`todos` コレクションを監視し、変更を表示に反映させるようにします

### コーディング
以下のファイルを追加・更新します

* `src/components/todo/Index.vue`
* `src/App.vue`


```vuejs

// src/components/todo/Index.vue
<template>
  <div>
    <h1>Index</h1>
    <table>
      <thead>
        <td>name</td>
      </thead>
      <tr v-for="todo in this.todos" :key="todo.id">
        <td>
          {{ todo.name }}
        </td>
      </tr>
    </table>
  </div>
</template>

<script>
import firebase from 'firebase'

export default {
  name: 'todoIndex',
  data: function () {
    return {
      db: null,
      todos: []
    }
  },
  created: function () {
    this.db = firebase.firestore()

    var _this = this
　　// todos コレクションを監視する
    this.db.collection('todos').onSnapshot(function (querySnapshot) {
      _this.todos = []
      querySnapshot.forEach(function (doc) {
        var data = doc.data()
        data.id = doc.id
        _this.todos.push(data)
      })
    })
  }
}
</script>
```

```vuejs

// src/App.vue
<template>
  <div id="app">
    <Add></Add>
    <Index></Index>
  </div>
</template>

<script>
import Add from './components/todo/Add.vue'
import Index from './components/todo/Index.vue'

export default {
  name: 'app',
  components: {
    Add,
    Index
  }
}
</script>

```



### 動作確認

追加ボタンで、`todos`コレクションにドキュメントを追加し、それが表示に反映されるかを確認します

http://localhost:8080/ を開き、追加ボタンを押すと、

![コメント 2019-12-09 234620.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/b4021ea5-8f20-b743-00d9-10977afc1b76.png)

ページが動的に更新されることを確認できます

![コメント 2019-12-09 234636.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175286/39758e06-34bf-4469-4420-57bbab2205f4.png)


# コード
最後に、ここまでで書いたコードをのせておきます

```js

// main.js
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

import firebase from 'firebase'
var firebaseConfig = {
  apiKey: [表示された値],
  authDomain: [表示された値],
  databaseURL: [表示された値],
  projectId: [表示された値],
  storageBucket: [表示された値],
  messagingSenderId: [表示された値],
  appId: [表示された値],
  measurementId: [表示された値]
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);

new Vue({
  render: h => h(App),
}).$mount('#app')

```


```vuejs
// src/components/todo/Add.vue
<template>
  <div>
    <h1>New TODO</h1>
    <div>
      <ul>
        <li><input v-model="name"></li>
        <li><button v-on:click="addTodo">Add</button></li>
      </ul>
    </div>
  </div>
</template>

<script>
import firebase from 'firebase'
import 'firebase/firestore';

export default {
  name: 'todoAdd',
  data: function () {
    return {
      db: null,
      name: ''
    }
  },
  created: function() {
    this.db = firebase.firestore()
  },
  methods: {
    addTodo: function () {
      var _this = this

      // todos コレクションにドキュメントを追加
      this.db.collection('todos').add({
        name: _this.name
      })
      .then(function () {
        // 追加に成功したら、name を空にする
        _this.name = ''
      })
      .catch(function () {
        // エラー時の処理
      })
    }
  }
}
</script>

```vuejs

// src/components/todo/Index.vue
<template>
  <div>
    <h1>Index</h1>
    <table>
      <thead>
        <td>name</td>
      </thead>
      <tr v-for="todo in this.todos" :key="todo.id">
        <td>
          {{ todo.name }}
        </td>
      </tr>
    </table>
  </div>
</template>

<script>
import firebase from 'firebase'

export default {
  name: 'todoIndex',
  data: function () {
    return {
      db: null,
      todos: []
    }
  },
  created: function () {
    this.db = firebase.firestore()

    var _this = this
　　// todos コレクションを監視する
    this.db.collection('todos').onSnapshot(function (querySnapshot) {
      _this.todos = []
      querySnapshot.forEach(function (doc) {
        var data = doc.data()
        data.id = doc.id
        _this.todos.push(data)
      })
    })
  }
}
</script>
```

```vuejs

// src/App.vue
<template>
  <div id="app">
    <Add></Add>
    <Index></Index>
  </div>
</template>

<script>
import Add from './components/todo/Add.vue'
import Index from './components/todo/Index.vue'

export default {
  name: 'app',
  components: {
    Add,
    Index
  }
}
</script>

```

# 最後に
Vue CLIでFirebaseを動作させる方法を紹介させていただきました


# 参考
Vue CLI
https://cli.vuejs.org/

Vue.js を vue-cli を使ってシンプルにはじめてみる
https://qiita.com/567000/items/dde495d6a8ad1c25fa43

Cloud Firestore データベースを作成する(公式)
https://firebase.google.com/docs/firestore/quickstart?hl=ja

Cloud Firestore を使ってみる(公式)
https://firebase.google.com/docs/firestore/quickstart?hl=ja

Cloud Firestore にデータを追加する(公式)
https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ja

Cloud Firestore でリアルタイム アップデートを入手する(公式)
https://firebase.google.com/docs/firestore/query-data/listen?hl=ja

Vue.js + FirebaseでTodoアプリを作る
https://qiita.com/magaya0403/items/e292cd250184ea3fe7b0