2018-11-25に更新

GAE+NuxtのSSRでFirestoreを使う

App Engineの標準環境でNuxtを使って無料SSR を先日やってみたので、今度はFirebaseのCloud Firestoreでデータの保存を試してみました。

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

※また後日記事を書きますが、通常セキュリティルールが入っているため、実際にはcloud functions経由でfirebase-adminを利用してデータを取ってくる必要があります。

Firebaseの初期設定

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

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で上記を読み込むようにしておきます。

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

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

Firestoreへのデータ追加&取得

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

テンプレート

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

<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>  

スクリプト

初期化

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

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

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

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

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

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を使うことは多いと思いますが、これはサーバーサイドレンダリングでは動作しないため、代わりにasyncDatafetchを使う必要があります。asyncDataは下記URLに使い方が載っていますが、async/awaitを使ったり、Promiseやcallback形式など自由に選べるようです。

非同期なデータ - Nuxt.js

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

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

データをFirestoreに追加する

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

  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にはリアルタイム アップデートの機能もありますので、一覧取得とかは頻繁に更新されるのであればそっちでやってみるのも良いかもしれません。

ツイッターでシェア
みんなに共有、忘れないようにメモ

だら@Crieit開発者

Crieitの開発者です。 Webエンジニアです(在宅)。大体10年ちょい。 記事でわかりにくいところがあればDMで質問していただくか、案件発注してください。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel, React, Flutter, Vue.js, Node, RoR 趣味:Elixir, Phoenix, Nuxt, Express, GCP, AWS等色々 PHPフレームワークちいたんの作者

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント