VuexFireでNuxt.jsアプリに一瞬でFirestoreを導入する

*今回のチュートリアルではNuxt.jsを使っていますが、全部フロントエンドで動いているのでVue.jsアプリでも同様に動きます。*

# TL;DR
サンプルコードは[Github](https://github.com/wataruoguchi/nuxtjs-firebase-example)にあります。
VuexFireを使ってNuxt.jsアプリでFirestoreからデータを取得しページに表示させます。また、ページ上のフォームからFirestoreにデータを追加します。

# はじめに
[前回の記事](https://qiita.com/wataruoguchi/items/fa9b59e21c4212293c04)でVuex.jsとFirebaseのCloud Functionsを使ってSSRアプリを作ってみました。
そのアプリをベースに、今回はVuexFireを使ってFirestoreを導入してみます。
FirestoreはFirebaseの提供するNoSQLデータベースです。現在はβ版ですが、今後Firebase Realtime Databaseに代わりFirebaseのデータベースサービスになっていくようです。

# Step 1: Firestore でコレクションを作ってみましょう
コレクションはRDBで言うところのテーブルです。ちなみにドキュメントはRDBのレコードに相当します。

作成するものは以下の通りです。
コレクション：`users`
ドキュメント：`users: { name: "test", email: "test@test.com" }`

[Cloud Firestore with Vue.jsで簡単なメモアプリを実装する](https://qiita.com/rubytomato@github/items/78087a2c69389f642760) by [@rubytomato@github](https://qiita.com/rubytomato@github) の[Firebaseにプロジェクトを作成する](https://qiita.com/rubytomato@github/items/78087a2c69389f642760#firebase%E3%81%AB%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B) にとても丁寧に説明されていたので、そちらを参考にして作ってみてください。

# Step 2: パッケージをインストールしてみましょう
私のFirebaseプロジェクト構成は以下の通りです。Nuxt.jsのプロジェクトは`src`の中にあります。

```
<proj>
L src
  L plugins
  L components
  L package.json
  L ...
L functions
L public
```

`src`に移動して`firebase`と`vuexfire`をインストールします。

- [VuexFire](https://github.com/posva/vuexfire/tree/firestore)


`cd src/ && yarn add firebase vuexfire@next`

# Step 3: コンフィグファイルを作成してみましょう

`serviceAccountKey.json`ファイルを作成します。今回は`<proj>`フォルダ内に作成します。

`<proj>`フォルダに移動して、ファイルを作成しましょう

`cd ../ && vi serviceAccountKey.json`

```serviceAccountKey.json
{
  "apiKey": "<API_KEY>",
  "authDomain": "<PROJECT_ID>.firebaseapp.com",
  "databaseURL": "https://<DATABASE_NAME>.firebaseio.com",
  "projectId": "<PROJECT_ID>",
  "storageBucket": "<BUCKET>.appspot.com",
  "messagingSenderId": "<SENDER_ID>"
}
```

API_KEYなどの情報は https://console.firebase.google.com/u/0/project/プロジェクト名/settings/general/ で確認することができます。

# Step 4: firebaseプラグインを作ってみましょう

`src`フォルダに移動して、`firebase.js`を`plugins`フォルダに作成します。

`cd src/ && vi plugins/firebase.js`

```plugins/firebase.js
import firebase from 'firebase'
import 'firebase/firestore'
const serviceAccount = require('~/../serviceAccountKey.json')

firebase.initializeApp({ ...serviceAccount })
const db = firebase.firestore()
const settings = { timestampsInSnapshots: true }
db.settings(settings)
export { db }
```

コンフィグファイルを元にfirebaseをイニシャライズし、dbをエクスポートしています。
`settings`を省略したところ、Browserのコンソールで追加するよう警告されました。

# Step 5: プラグインをNuxt.jsで使えるように設定ファイルを編集しましょう

`src`フォルダにいることを確認してください。`nuxt.config.js`を編集してpluginを使えるよう設定します。

`vi nuxt.config.js`

```nuxt.config.js
module.exports = {
  ...
  plugins: ['~/plugins/firebase'],
  ...
}
```

# Step 6: Vuex用のstoreファイルを作成してみましょう

`src`フォルダにいることを確認してください。`store`フォルダの中に`index.js`を作成して編集していきます。

`vi store/index.js`

```store/index.js
import Vuex from 'vuex'
import { firebaseMutations, firebaseAction } from 'vuexfire'

const createStore = () => {
  return new Vuex.Store({
    state: {
      users: [],
    },
    mutations: {
      ...firebaseMutations
    },
    actions: {
      setUsersRef: firebaseAction(({ bindFirebaseRef }, ref) => {
        bindFirebaseRef('users', ref)
      })
    },
    getters: {
      getUsers: (state) => {
        return state.users
      },
    },
  })
}

export default createStore
```

ここで特別なところは以下の`vuexfire`を使っているところです。
- `import { firebaseMutations, firebaseAction } from 'vuexfire'`
- `mutations`
- `actions.setUsersRef`

でもたったこれだけです。

# Step 7: ページに表示させてみましょう

`src`フォルダにいることを確認してください。`pages/users.vue`を編集して、Step 1で作ったコレクションを表示させてみましょう。

```pages/users.vue
<template>
  <div>
    <h1>firestore contents here</h1>
    <ul>
      <li v-for="(user, userIdx) in users" :key="userIdx">
        <ul>
          <li>name: {{ user.name }}</li>
          <li>email: {{ user.email }}</li>
        </ul>
      </li>
    </ul>
  </div>
</template>

<script>
import { db } from '~/plugins/firebase.js'
import { mapGetters } from 'vuex'

export default {
  created: function () {
    this.$store.dispatch('setUsersRef', db.collection('users'))
  },
  computed: {
    ...mapGetters({ users: 'getUsers' })
  },
}
</script>

<style>
</style>
```

`created`でFirestoreのusersをバインドし、computedにてVuex経由でusersをフェッチしてテンプレートで表示させています。

`src`フォルダ内で`yarn dev`を実行してみてください。サーバーが無事に起動したら http://localhost:3000/users をブラウザで開いてみてください。無事にコレクションが表示されましたか？おめでとうございます！
[前回の記事](https://qiita.com/wataruoguchi/items/fa9b59e21c4212293c04)から続けてくださっている場合、エラーが出るかもしれません。[このコミット](https://github.com/wataruoguchi/nuxtjs-firebase-example/commit/40942d98e68f17d065b864e06cfbd60805a1716b)を追加して、再度`yarn dev`を実行してみてください。

# Step 8: ページからコレクションを追加してみましょう

`pages/users.vue`にフォームみたいなものを足してみましょう。

```diff

<template>
  <div>
    <h1>firestore contents here</h1>
    <ul>
      <li v-for="(user, userIdx) in users" :key="userIdx">
        <ul>
          <li>name: {{ user.name }}</li>
          <li>email: {{ user.email }}</li>
        </ul>
      </li>
    </ul>
+    <div class="form">
+      <h1>I know, but this is the form!</h1>
+      <div>
+				Name: <input type="text" name="name" v-model="name">
+      </div>
+      <div>
+				email: <input type="text" name="email" v-model="email">
+      </div>
+      <div>
+        <button @click="submit">Submit</button>
+      </div>
+    </div>
  </div>
</template>

<script>
import { db } from '~/plugins/firebase.js'
import { mapGetters } from 'vuex'

export default {
  created: function () {
    this.$store.dispatch('setUsersRef', db.collection('users'))
  },
  computed: {
    ...mapGetters({ users: 'getUsers' })
  },
+  data: function () {
+    return {
+      name: '',
+      email: '',
+    }
+  },
+  methods: {
+    submit: function () {
+      const user = {
+        name: this.name,
+        email: this.email,
+      }
+      const usersRef = db.collection('users')
+      usersRef.add(user)
+      this.name = ''
+      this.email = ''
+    }
+  },
}
</script>

<style>
</style>
```

`const usersRef = db.collection('users')`でFirestoreのusersを参照し、そこにuserを追加しています。
実際にフォームに入力してみると、入力値がFirebase, Vuexを経由してフォームの上のリストに追加される様子がわかります。

同様に、Firebase ConsoleをみてみるとFirestoreにもデータが追加されていることがわかります。

# おわりに
無事にFirestoreの第一歩が踏み出せたことを祈っています。次のステップとしてはFirestoreのセキュリティ設定などになってくるかと思います。Pros/ConsありますがServerlessは楽ですね。

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