vue.jsとFirebaseのRealtime DatabaseとAuthorization機能を利用したSlackクローンの構築を複数回にわけて行います。1回目の本文書ではチャットのリアルタイム更新に重要な役割をするFirebaseのRealtime Databaseの使用方法に重点をおいて説明を行っています。読み終えると下記を理解することができます。

  • Vue.jsからのFirebaseのRealtime Databaseへの書き込み、読み込み
  • Vue.jsとFirebaseのイベントを利用したリアルタイム更新機能の理解

vue.jsプロジェクトの作成

vue/cliパッケージのインストールが完了している場合はvue createコマンドでプロジェクトの作成を行います。vue/cliパッケージのインストールを行っていない場合はnpxコマンドを利用してプロジェクトの作成を行います。ここではプロジェクトの名前はvue_slack_cloneにしていますが任意の名前をつけてください。


 $ vue create vue_slack_clone
 or
 $ npx vue create vue_slack_clone

createコマンド実行後に表示されるManually select featuresではBabel, Router, Vuex, Linter / Formatterを選択して進めます。

インストールが完了したらプロジェクトディレクトリに移動してコンパイルを行います。


 $ cd vue_slack_clone
 $ npm run serve

ブラウザを起動してvue.jsの初期画面が表示されるか確認を行ってください。

vue.jsプロジェクトの初期画面
vue.jsプロジェクトの初期画面

Firebaseの設定

アカウントの登録

Firebaseのユーザアカウントがない人はFirebaseのアカウントの登録が必要になります。アカウントの登録については下記の文書の”アカウントの登録”を参考に行ってください。

アカウント登録時にクレジットカード等の入力は必要なく無料の範囲で動作確認を行うことができます。

プロジェクトの作成

アカウントの登録が完了したらFirebaseの管理画面からプロジェクトの作成を行う必要があります。

プロジェクトの作成ボタンをクリックしてください。

プロジェクトの新規作成
プロジェクトの新規作成

プロジェクトの名前を入力してください。ここではvue-slack-cloneという名前にしています。

プロジェクトの名前を入力
プロジェクトの名前を入力

Googleアナリティクスに関する設定ですが、動作確認なので無効にしてください。無効後にプロジェクトを作成するボタンをクリックしてください。

google Analyticsの設定
google Analyticsの設定

プロジェクトの作成完了まで少し時間がかかります。完了すると続行するボタンが表示されるのでクリックしてください。

プロジェクト作成中
プロジェクト作成中

クリックすると以下のプロジェクトの概要画面が表示されます。

管理画面
プロジェクト概要画面

Realtime Databaseの作成

左側の開発メニューの2番目にあるDatabaseをクリックしてください。クリック後にRealtime Databaseの選択画面までスクロールして”データベースを作成”ボタンをクリックしてください。

Realtime Database選択
Realtime Database選択

Realtime Dabaseのセキュリティルールの設定画面が表示されますが動作確認を行いたいので読み取り書き込みがすべて許可されているテストモードで開始を選択して、”有効にする”をクリックしてください。

データベースの作成
データベースの作成

有効にするボタンをクリックすると以下の画面が表示されます。vue-slack-clone-1881a1がデータベースで何もデータが入っていないのでnullと表示されています。データを保存するとこの画面に保存したデータが表示されます。

データベースの作成完了
データベースの作成完了

アプリケーションの追加

vue.jsなど外部のアプリケーションからFirebaseのデータベースに接続するためには接続情報が必要となります。

プロジェクトの概要画面に戻り画面中央の赤丸</>をクリックしてください。

アプリの追加ボタン
アプリの追加ボタン

アプリのニックネームを入力してアプリを登録ボタンをクリックしてください。

ウェブアプリの設定
ウェブアプリの設定

FirebaseのSDKが表示されます。このスクリプトをvue.jsプロジェクトのmain.jsファイルに貼り付ける必要があります。

アプリケーションのSDK
アプリケーションのSDK

下記のデータをそのまま貼り付けても動作しないので各自でFirebaseの管理画面からSDKの情報を取得してください。


import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import firebase from "firebase/app";

Vue.config.productionTip = false;

var firebaseConfig = {
  apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXX",
  authDomain: "vue-slack-3796e.firebaseapp.com",
  databaseURL: "https://vue-slack-3796e.firebaseio.com",
  projectId: "vue-slack-3796e",
  storageBucket: "vue-slack-3796e.appspot.com",
  messagingSenderId: "896148090732",
  appId: "XXXXXXXXXXXXXXXXXXXXXXXXXX9"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);

window.firebase = firebase;

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount("#app");

main.jsの上部でfirebaseをimportしていますがfirebaseライブラリはインストールされていないのでこれからfirebaseのライブラリのインストールを行います。インストールはnpmコマンドで行います。


 $ npm install --save firebase

Firebaseの動作確認

データベースの初期設定が完了したのでvue.jsからのFirebaseのRealtime Databaseに対して読み書きを行う方法を確認していきます。

MySQLなどのデータベースではデータベース作成後にテーブルや列情報のスキーマを事前に作成する必要がありますがReadtime Databaseでは必要ではありません。リレーショナルデータベースに慣れている人の場合どのようにデータを登録するのか疑問に思うかもしれませんが下記の手順のままに進めてください。

Firebaseのデータベースへの書き込み

vue.jsのプロジェクトのsrc¥viewsの下にあるHome.vueファイルを使ってデータベースへの書き込みの動作確認を行います。Firebaseにデータを書き込む方法はset, pushと2つあります。両方の動作確認を行い違いを確認します。

setによるデータベースへの書き込み

setによるデータベースの書き込みは下記のように記述することで行うことができます。slack等の名前がでてきますがデータ登録後にこのslackがどこに対応するのかがわかるのでこのまま進めてください。


firebase.database().ref("slack")
  .set({
    content: this.message,
    user: {
      name: "John Doe"
    }
  }

実際にsetによる書き込みを追加したコードは下記のようになります。input要素にv-modelでmessageを設定し入力した値をFirebaseのデータベースに追加します。


<template>
  <div>
    <h1>Firebaseを使った読み書き確認</h1>
    <input v-model="message" />
    <button @click="addMessage">メッセージを追加</button>
  </div>
</template>

<script>
import firebase from "firebase/app";
import "firebase/database";

export default {
  name: "Home",
  data() {
    return {
      message: "",
    };
  },
  methods: {
    addMessage() {
      firebase.database().ref("slack")
        .set({
          content: this.message,
          user: {
            name: "John Doe"
          }
        });
    }
  }
};
</script>
firebaseのimportの2行も忘れずに追加をしてください。

実際にブラウザを使ってデータの追加を行います。input要素に”はじめてのメッセージ”を入力してメッセージを追加ボタンをクリックします。

メッセージ入力画面
メッセージ入力画面

Firebaseの管理画面でデータベースに入力されたデータを確認します。先程refの中で設定していたslackを確認することができます。そのslackの下にcontentとuser、さらにuserの下にnameとツリー構造になっていることが確認できます。

データベースでのデータ確認
データベースでのデータ確認

slackという名前に決まりはなくmessageなど他の名前についても問題ありません。contentやuserを含め任意の名前をつけることができます。

pushによるデータベースへの書き込み

pushによる書き込みも確認します。コードは先程のsetをpushに変更するだけです。


firebase.database().ref("slack")
  .push({
    content: this.message,
    user: {
      name: "John Doe"
    }
  }
push(object)ではなくpushを実行した後にsetというpush().set(object)でも問題ありません。

setからpushに変更しただけなので入力画面は変わりません。

追加のメッセージ
追加のメッセージ

メッセージを追加後にFirebase管理画面でデータベースの中身を確認するとFirebase側で一意のキーが自動で付与されます。pushに変更することで一意のキーが付与されます。

pushでデータを追加した場合
pushでデータを追加した場合

一意のキーによりメッセージを識別することができるのでここからはpushを利用してデータベースへのデータの登録を行っていきます。

setで書き込んだデータはFirebase管理画面から削除を行って行ってください。データの上にカーソルを乗せるとXが表示されるのでXをクリックして削除してください。

Firebaseのデータベースからの読み込み

Firebaseではイベントによりデータベースへのデータの追加や更新が行われるとその処理をブラウザにリアルタイムに反映させることができます。この機能のおかげでユーザがメッセージを追加すると別のブラウザを閲覧しているユーザにも追加したデータが即座に反映されます。この機能がSlackのようなチャットで重要な役割を持っています。

Firebaseからのデータの取得方法にも書き込みと同様にいくつか方法があるのでここではvalueイベントとchild_addedイベントを使ってデータの取得を行います。

valueイベントによるデータ取得

valueイベントを利用したデータベースからのデータ取得は下記のように記述します。onでvalueイベントを設定するとrefで指定したslack以下に登録されたすべてのデータを一括で取得することができます。一括取得は1回ではなくslackにデータが追加される度に一括でデータが取得されます。


firebase.database().ref("slack")
  .on("value", snapshot => console.log(snapshot.val()));
}

vue.jsのライフサイクルフックのmountedにデータ取得のコードを追加することでブラウザでアクセスすると自動でFirebaseのデータベースからデータ取得を行います。


mounted() {
 firebase.database().ref("slack")
   .on("value", snapshot => console.log(snapshot.val()));
 }
}

ブラウザでページにアクセスしてデベロッパーツールのコンソールを見るとデータベースから取得したデータ(2件)を確認することができます。2つのデータはpushで追加しているので一意のキーも確認できます。

データベースからデータ取得
データベースからデータ取得

ブラウザ上からメッセージの追加を行うと追加したデータを含めすべてのデータ(3件分)が取得されていることがわかります。

メッセージを追加した直後に自動でコンソールログに表示されます。

追加したデータを即座に取得
追加したデータを即座に取得

ここまでの動作確認によりvalueイベントではすべてのデータが一括で取得できることを理解しておいてください。

child_addedイベントによるデータ取得

valueからchild_addedイベントに変更を行い動作確認を行います。child_addedと名前の通りchild(子)にadded(追加された)されたらイベントが発生しデータの取得が行われます。


mounted() {
 firebase.database().ref("slack")
   .on("child_added", snapshot => console.log(snapshot.val()));
 }
}

ブラウザを開いて確認するとvalueとは異なりデータが1行ごとに分かれていることが確認できます。またすべてのデータ(3件)が取得させていることもわかります。

child_addedイベントによる取得
child_addedイベントによる取得

次にデータの追加を行ってみましょう。valueイベントは異なりすべてのデータを追加の度に取得するのではなく追加した情報のみ取得していることがわかります。

child_addedでデータを追加
child_addedでデータを追加

child_addedイベントでは最初はすべてのデータを取得し、その後はデータが追加されると追加したデータのみ取得できることがわかりました。

v-forによる取得したデータの表示

valueイベント、child-addedイベントによりデータベースからデータが取得できることは確認できたので取得したデータをv-forディレクティブを利用してブラウザに表示させます。

valueイベント、child-addedイベントどちらでも実現できますがここではvalueイベントを利用して行います。

vue.jsのデータプロパティにmessagesを追加してデータベースから取得したデータをライフサイクルフックのmountedで挿入しています。messagesはv-forを利用して展開させています。各データに自動的に付与されているキーをindexで意図的に表示しています(通常は表示させる必要はありません)。このキーを利用することでデータの更新、削除を行うことができます。


<template>
  <div>
    <h1>Firebaseを使った読み書き確認</h1>
    <input v-model="message" />
    <button @click="addMessage">メッセージを追加</button>
    <ul>
      <li v-for="(message, index) in messages" :key="index">
        {{ message.content }} index:{{ index }}
      </li>
    </ul>
  </div>
</template>

<script>
import firebase from "firebase/app";
import "firebase/database";

export default {
  name: "Home",
  data() {
    return {
      message: "",
      messages: []
    };
  },
  methods: {
    addMessage() {
      firebase.database().ref("slack")
        .push({
          content: this.message,
          user: {
            name: "John Doe"
          }
        });
    }
  },
  mounted() {
    firebase.database().ref("slack")
      .on("value", snapshot => (this.messages = snapshot.val()));
  }
};
</script>
v-forを使いデータベースのデータを表示
v-forを使いデータベースのデータを表示

リアルタイムで追加されるメッセージの動作確認

データベースからの書き込みと読み込みの設定が完了すると複数のブラウザでリアルタイムにデータが追加される機能を確認することができます。

2つのブラウザを起動してください。片方のブラウザで下記のようにメッセージを追加しinput要素に記述しメッセージ追加ボタンをクリックしてください。

片方のブラウザからメッセージを追加
片方のブラウザからメッセージを追加

追加後に両方のブラウザで追加したメッセージが即座にブラウザ上に追加されることを確認してください。リアルタイムでの反映が行えることが確認できます。

追加したメッセージが即座に反映
追加したメッセージが即座に反映
ユーザ認証やチャネルなどの設定は行っていないのでだれでもメッセージを書き込める状態です。今後ユーザ認証やチャネルなどの機能を追加していきます。

データの削除方法

v-forで展開した際に表示したindexを利用してデータの削除方法も確認しておきます。各メッセージにspanタグを追加しクリックイベントでdeleteMessageメソッドを追加します。引数にはindexを設定します。


<ul>
  <li v-for="(message, index) in messages" :key="index">
    {{ message.content }} index:{{ index }}
    <span @click="deleteMessage(index)">X</span>
  </li>
</ul>

vue.js側の設定ではclickイベントで受け取ったindexを利用してFirebaseのデータベースからそのindexを持つデータを削除します。そのコードは下記の通りです。slackの子(child)で指定したindexを持つデータを指定してremoveで削除しています。


deleteMessage(index) {
  firebase
    .database()
    .ref("slack")
    .child(index)
    .remove();
}

ブラウザ上でメッセージに右にあるXを押すとそのメッセージがブラウザ上から削除されることを確認してください。valueイベントでは削除後のすべてのデータを再度取得するためvue.js側でmessagesの削除処理を行う必要はありません。

まとめ

vue.jsからFirebaseのRealtime Databaseへのデータの書き込み、読み込み、削除またブラウザを利用したリアルタイムでの更新を実現することができました。この機能を活用すればSlackのようなチャットアプリが作成できることがこの時点で理解できるかと思います。

続きは今後別の文書で公開していきます。