GAE+NuxtのSSRでFirestoreを使う
Tags: vue, nuxt, gae, firebase
Published: 2018-08-03 13:06:02

---
title: GAE+NuxtのSSRでFirestoreを使う
published: true
description: 
tags: vue,nuxt,gae,firebase
canonical_url: https://crieit.net/posts/GAE-Nuxt-SSR-Firestore
---

[App Engineの標準環境でNuxtを使って無料SSR](https://crieit.net/posts/App-Engine-Nuxt-SSR) を先日やってみたので、今度はFirebaseのCloud Firestoreでデータの保存を試してみました。

ちなみにGAEのスタンダード環境ではNode8が動くため、ローカルでも全てNode8で動かす必要があります。

## Firebaseの初期設定

plugins/firebase.jsに下記のように設定を保存します。

```javascript
import * as firebase from "firebase";
require("firebase/firestore");

if (!firebase.apps.length) {
  const config = {
    apiKey: "your firebase api key",
    authDomain: "your firebase auth domain",
    databaseURL: "your firebase database url",
    projectId: "your google cloud platform project id",
    storageBucket: "your google cloud platform storage bucket",
    messagingSenderId: "your firebase messaging sender id"
  };
  firebase.initializeApp(config);
}

firebase.firestore(); // もしかしたら要らないかも
```

そしてnuxt.config.jsで上記を読み込むようにしておきます。

```javascript
  plugins: ["~/plugins/firebase.js"],
```

これでFirebaseのライブラリがNuxt上で利用できるようになります。

## Firestoreへのデータ追加＆取得

元々あるindex.vueを下記のように修正し、データの一覧を追加してボタンを押すとデータを登録できるようにした最小のサンプルを作ってみました。（関係ないところは削っています）

### テンプレート

テンプレートは単にデータを表示しているだけで特筆するところは無いです。

```html
<template>
  <section class="container">
    <div>
      <div v-for="text in texts" :key="text.id">
        {{ text.body }}
      </div>
      <input type="text" v-model="textInput">
      <button type="button" @click="add">add</button>
    </div>
  </section>
</template>
```

### スクリプト

#### 初期化

```javascript
import db from "../lib/db";
```

DBを簡単に使える様にインポートしてすぐ使えるようにしています。これは別に必ず作らなければならないわけではありません。中身は単にdbを初期化して取ってきているだけです。

```
import * as firebase from "firebase";
export default firebase.firestore();
```

#### データをFirestoreから取得してくる

ページを読み込むと、まずFirestoreからデータを取ってきて一覧します。

```javascript
async function getTexts() {
  return new Promise(callback => {
    let texts = [];
    db
      .collection("texts")
      .get()
      .then(query => {
        query.forEach(doc => {
          texts.push(doc.data());
        });
        callback(texts);
      });
  });
}

export default {
  data() {
    return {
      texts: [],
      textInput: ""
    };
  },
  async asyncData({ params }) {
    return { texts: await getTexts() };
  }
}
```

データの初期化にmountedを使うことは多いと思いますが、これはサーバーサイドレンダリングでは動作しないため、代わりに`asyncData`や`fetch`を使う必要があります。`asyncData`は下記URLに使い方が載っていますが、async/awaitを使ったり、Promiseやcallback形式など自由に選べるようです。

[非同期なデータ - Nuxt.js](https://ja.nuxtjs.org/guide/async-data/)

あとこの中では`this`が使えないため、仕方なく適当にクラスの外にfunctionを定義してそれを呼び出しています。

あ、あとasyncDataはコンポーネントでは使えないため、今回はページ上で実行しています。実際の開発の際もコンポーネントで値を使いたい場合はプロパティで渡すか、storeを使うかになると思います。

#### データをFirestoreに追加する

あとは追加ボタンをクリックした時の処理を追加します。

```javascript
  methods: {
    add() {
      db
        .collection("texts")
        .add({
          body: this.textInput
        })
        .then(docRef => {
          this.textInput = "";
          return getTexts();
        })
        .then(texts => (this.texts = texts));
    }
  }
```

追加してとりあえず先程の一覧取得処理を実行しているだけです。

これでFirestoreにデータが保存され、画面上にも表示されます。Firebase Consoleのデータ一覧でも確認できます。

## サーバーサイドレンダリングされているか確認

Google App Engineで動作させればサーバーサイドレンダリングされますので、一度ページをリロードして確認すればソース上に登録した文字列が存在するのが確認できると思います。（間違って`mounted`で処理しているとSSRされません）

FIrebaseだとデプロイもあっというまでサーバー側の処理とか何も気にしないでいいので楽ですね！

あとはFirestoreには[リアルタイム アップデート](https://firebase.google.com/docs/firestore/query-data/listen?hl=ja)の機能もありますので、一覧取得とかは頻繁に更新されるのであればそっちでやってみるのも良いかもしれません。