皆見飽きただろうNuxt.js with Firebase入門


12周ぐらい回って誰もが飽きているNuxt.jsとFirebaseの組み合わせですが、いくら記事を読んでもやっぱり自分で書いてみないとわからないものがあるわけで、散々出回っているgetting-started記事だけど自らの記録という意味も含めて書いてみます。

# Nuxt.js

https://ja.nuxtjs.org/

> Nuxt.js は Vue アプリケーションを作成するフレームワークです。ユニバーサルアプリケーション、静的に生成されるアプリケーション、シングルページアプリケーションの中から作成するアプリケーションを選ぶことができます。

よくNuxt.jsを説明するときにサーバーサイドレンダリングについて言及されることが多いけど、javascriptを使ってサーバーサイドレンダリングするメリットがよくわかってない。それならLLでもよくないですか？？

# Firebase

https://firebase.google.com/?hl=ja

モバイルアプリケーションやWebアプリケーションのためのGoogleのバックエンドサービス。これによってサーバーレスアーキテクチャを実現出来たりする。認証やDB、ホスティングなど様々なサービスがある。

# つまり?

LLでもいいのではという疑問が出たが、Nuxt.jsとFirebaseを使うことで、モバイルアプリエンジニアやフロントエンドエンジニアでも、サーバーサイドやインフラの知識をそれほど必要としないでバックエンド開発が出来る。

# 今回作ったもの

Nuxt.jsとFirebase Cloud Firestoreを使って一行日記を記録出来るシンプルなWebアプリケーション。

https://github.com/kiyc/one-liner-diary

## 開発環境

macOS Sierra 10.12.6
Node v10.8.0
Yarn 1.9.4(最新の1.12.3にしたらエラーとなったので…)

# まずNuxt.js

## インストール

プロジェクト名は"one-liner-diary"としました。

```
$ yarn create nuxt-app one-liner-diary --edge
$ cd one-liner-diary
$ yarn run dev
```

![スクリーンショット 2018-12-16 19.35.27.png](https://qiita-image-store.s3.amazonaws.com/0/123511/2242ce58-9e88-c2d4-978c-2de452a9a44c.png)

ブラウザでlocalhostにアクセスするとロゴの画面が表示されます。
超簡単。というか最近はどのフレームワークやライブラリでも初心者に優しいのがありがたい。

## 新しい画面を追加してみる

pages以下に新しいVueファイルnewdawn.vueを追加。
layouts/default.vueのサイドナビゲーションにもその画面へのリンクを追加します。
ファイル名がそのままルーティングになるのがわかりやすいです。
`yarn run dev`でホットリロードされて、サイドナビゲーションから新しい画面に遷移出来ます。簡単だ…。

![スクリーンショット 2018-12-16 19.49.33.png](https://qiita-image-store.s3.amazonaws.com/0/123511/12eac847-e9d6-ad84-2ff3-4a3525cc9128.png)
![スクリーンショット 2018-12-16 19.49.44.png](https://qiita-image-store.s3.amazonaws.com/0/123511/e2746e12-862b-f67c-b6df-358e4549b55f.png)

## Vuexを使って一行日記を実装

ここは主題ではないので省略。VuexとVuetifyを使って簡単な日記機能を実装。
以下がそのコミットです。
store/index.jsを追加すると自動でVuexが有効になるのが便利。

https://github.com/kiyc/one-liner-diary/commit/a24ea3a597f21524f49edf407b3eedf3e73498c5

躓いた点としては、Vuetifyで以下のESLintのエラーが出たので、そのルールだけ除外しました。

```
error  Require self-closing on Vue.js custom components (<v-text-field>)  vue/html-self-closing
```

![スクリーンショット 2018-12-16 21.20.18.png](https://qiita-image-store.s3.amazonaws.com/0/123511/bd636a8a-876c-b685-d3c1-e41e222507dd.png)

# 次にFirebase Cloud Firestore

https://firebase.google.com/products/firestore/?hl=ja

FirebaseのデータベースにはRealtime DatabaseとCloud Firestoreがある。今回はまだベータ版だがCloud Firestoreを使ってみました。どちらもNoSQLデータベース。
まずFirebaseのプロジェクトがない場合はプロジェクトを登録します。
その後、FirebaseコンソールからFirestoreのデータベースを作ります。
Firestoreはコレクションとドキュメントから構成される。なんとなくjsonっぽいのでjavascriptとも相性がいいのだろう。
コンソールからいくつかデータを登録しておきます。

![スクリーンショット 2018-12-16 21.49.10.png](https://qiita-image-store.s3.amazonaws.com/0/123511/7c850102-5e9e-c436-066b-12da0ff38c08.png)

次にfirebaseとvuexfireをインストール。これでVuex経由でFirestoreを操作出来るようになります。

```
$ yarn add firebase vuexfire@next
```

FirebaseコンソールにはAPIキーの情報があるので、それをソースコードにコピペ。
参考URLの記事にも書かれていたけど、settingsを記述しないとブラウザで警告が出ます。
調べたところAPIキーは隠さなくてもいいらしい(しかし自分はjsonに分けてコミットから外した)。

```config.js
const config = {
  apiKey: "APIキー",
  authDomain: ...
  databaseURL: ...
}

export default config
```

```plugins/firebase.js
import firebase from 'firebase'
import config from '@/config'

if (!firebase.apps.length) {
  firebase.initializeApp(config)
}

const db = firebase.firestore()
const settings = { timestampsInSnapshots: true }
db.settings(settings);

export { db }
```

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

const store = () => {
  return new Vuex.Store({
    state: () => ({
      notes: [],
    }),
    mutations: {
      ...firebaseMutations
    },
    actions: {
      setNotesRef: firebaseAction(({ bindFirebaseRef }, ref) => {
        bindFirebaseRef('notes', ref)
      }),
      saveNote ({ commit, state }, note) {
        let notes = state.notes
        notes.push({ content: note })
        commit('setNotes', notes)
      },
    },
    getters: {
      getNotes: (state) => {
        return state.notes
      },
    },
  })
}

export default store
```

```pages/index.vue
<template>
  <v-layout
    justify-center
    align-center
    row
    wrap>
    <v-flex
      xs12
      mb-2>
      <v-text-field
        v-model="newNote"
        label="日記を書こう！"
        @keyup.enter="saveNote"
      ></v-text-field>
      <v-btn
        color="success"
        @click="saveNote">
        Send
      </v-btn>
    </v-flex>
    <v-flex
      v-for="(note, i) in notes"
      :key="i"
      xs12
      mb-2>
      <v-card>
        <v-card-text>
          {{ note.content }}
        </v-card-text>
      </v-card>
    </v-flex>
  </v-layout>
</template>

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

export default {
  data () {
    return {
      newNote: '',
    }
  },
  computed: {
    ...mapGetters({ notes: 'getNotes' })
  },
  mounted () {
    this.$store.dispatch('setNotesRef', db.collection('notes'))
  },
  methods: {
    saveNote () {
      if (!this.newNote.length) {
        return
      }

      const newNote = { content: this.newNote }
      this.newNote = ''

      db.collection('notes').add(newNote)
    },
  },
}
</script>
```

![スクリーンショット 2018-12-16 22.48.05.png](https://qiita-image-store.s3.amazonaws.com/0/123511/d457e466-c28e-08d3-a517-1d5273b3af5b.png)

![スクリーンショット 2018-12-16 22.48.47.png](https://qiita-image-store.s3.amazonaws.com/0/123511/3a74e9dd-3e09-8c27-fbd8-08f426f25b79.png)

![スクリーンショット 2018-12-16 22.53.15.png](https://qiita-image-store.s3.amazonaws.com/0/123511/b43ae4df-3aa8-8127-b9f2-8a1176c34a68.png)

なんか中途半端な順番でデータが追加されているけど、とりあえずブラウザからFirestoreへのデータ登録は出来ました。

# Firebase AuthenticationでGoogle認証

も書くつもりだったのだが力尽きたので次の記事に続きます。

#### 追記

書きました。

https://qiita.com/kiyc/items/322b354290f95dbe3276

# 参考URL

https://qiita.com/potato4d/items/cfddeb8732fec63cb29c
https://qiita.com/cyokodog@github/items/eeedc5c94477602ec9f3
https://qiita.com/wataruoguchi/items/8fdda8e9754658be06be