Help us understand the problem. What is going on with this article?

Firebase + Vue.jsで認証付き簡易チャットアプリ作成

github
https://github.com/ebatetsu/firebase_vue_chat

Firebaseプロジェクト作成

https://console.firebase.google.com/?hl=ja
ここからプロジェクトを作成

Vue.jsの開発環境構築

Vue CLIを使用するのでインストール
$ npm install -g vue-cli

任意のディレクトリでプロジェクトフォルダ作成
$ vue init webpack [project_name]

とりあえず全部EnterでOKです。

ディレクトリ移動
$ cd [project_name]

パッケージをインストールする
$ npm install

sassで書きたかったら
$ npm install sass-loader node-sass --save-dev

ローカルサーバー起動
$ npm run dev

http://localhost:8080
にアクセスして
sample_app.png
これが表示されればOKです。

Firebaseプロジェクトとの紐付け

Firebase CLIのインストール&ログイン
$ npm install -g firebase-tools
$ firebase login

初期化コマンド
$ firebase init
スクリーンショット 2018-10-11 12.58.38.png
こんな画面になり、今回はDatabase、Hostingだけ使用するのでSpaceで選択してEnter

Firebaseプロジェクト選択では先ほど作成したプロジェクトを選択

基本Enterで進んでいくが、
「What do you want to use as your public directory?」
publicディレクトリを聞かれた際は、最終的にVue CLIで開発したものをビルドして./distディレクトリに吐き出すのでdistと入力

一旦Firebaseにデプロイしてみる

Vueをビルドする
$ npm run build

Firebaseにデプロイ
$ firebase deploy

Firebase管理面の「Hosting」から確認できます。

Firebaseをアプリに追加

左上の歯車マークから設定画面に遷移し、「ウェブアプリに Firebase を追加」をクリック
sample app – 設定 – Firebase console.png
表示されたスニペットをコピーし
./index.html
</body>直前に貼り付ける

Google認証を有効化

管理画面 → Authentication → ログイン方法 → googleからステータスを有効にしてメールアドレスを選択して保存
sample app – Authentication – Firebase console.png

データベース作成

管理画面 → Database
からRealtime Databaseを選択
sample app – Database – Firebase console.png

セキュリティルールは設定しなおすのでどちらでも大丈夫です。

./database.rules.json
に以下のように記述
https://github.com/ebatetsu/firebase_vue_chat/blob/master/database.rules.json

  • 読み込みは制限なし
  • 書き込みは認証が必要
  • 認証時のnameデータと書き込み時のnameデータは一致していないといけない
  • textデータは300文字以下でないといけない

みたいな設定をしています。

詳しくは公式のFirebase Realtime Database ルールについてを見てください。

データベース設定だけデプロイ
$ firebase deploy --only database

管理画面から反映を確認
sample app – Database – Firebase console (2).png

実装(ようやく。。)

認証部分実装

雛形となる部分を実装していきます。

./src/App.vue
に以下のように記述
https://github.com/ebatetsu/firebase_vue_chat/blob/master/src/App.vue

サインイン・サインアウト機能は非常に簡単に実装できます。

signIn () {
  const provider = new firebase.auth.GoogleAuthProvider()
  firebase.auth().signInWithPopup(provider)
},
signOut () {
  firebase.auth().signOut()
},

ユーザーがログインしているかどうかでボタンのテキストやfunctionを切り替えています。

onAuthStateChanged () {
  firebase.auth().onAuthStateChanged( user => {
    this.userName = user ?
      this.getUserName() : null

    this.userPic = user ?
      this.getProfilePicUrl() : null

    this.authButtonText = user ?
      'Sign-out' : 'Sign-in with Google'

    this.authFunction = user ?
      this.signOut : this.signIn

    this.isSignedIn = user ?
      true : false
  })
},
<button class="header__auth-button" @click="authFunction">
  {{ authButtonText }}
</button>

下記部分は子コンポーネントに値を渡しています。

<router-view
  :isSignedIn="isSignedIn"
  :userName="userName"
  :userPic="userPic"
>
</router-view>

ルート設定

./src/components/HelloWorld.vue
を任意の名前に変更する
./src/components/Chat.vue

./src/router/index.js
を以下のように記述
https://github.com/ebatetsu/firebase_vue_chat/blob/master/src/router/index.js

これでTOPにアクセスすると<router-view></router-view>./src/components/Chat.vueの内容が表示される

チャット部分実装

./src/App.vue
<router-view></router-view>に入る部分を実装していきます。

以下のように記述
https://github.com/ebatetsu/firebase_vue_chat/blob/master/src/components/Chat.vue

データベース設定でもバリデーションを入れていましたがjs側でもログイン状態を確認しつつ値が空ではないこともチェックし、問題なければ'/messages/'配列に追加する

postMessage () {
  let that = this
  if (!that.isSignedIn || !that.message) return
  firebase.database().ref('/messages/').push({
    name: that.userName,
    text: that.message,
    profilePicUrl: that.userPic
  })
  .then( data => {
    that.errorMessage = null
    that.message = null
  })
  .catch( error => {
    that.errorMessage = '正しく入力してください'
  })
},

データベースから値を取ってきて

loadMessages () {
  firebase.database().ref('/messages/').on('value', (snapshot) => {
    if (snapshot) {
      let rootList = snapshot.val()
      let messageList = []
      Object.keys(rootList).forEach((val, key) => {
        rootList[val].id = val
        messageList.push(rootList[val])
      })
      this.messageList = messageList
    }
  })
}

messageListにプッシュ

data () {
  return {
    messageList: []
  }
},

v-forで表示する

<li v-for="list in messageList">
  <div class="conversation__user-image"><img :src="list.profilePicUrl" alt=""></div>
  <div class="conversation__col">
    <p class="conversation__user-name">{{list.name}}</p>
    <p class="conversation__user-text">{{list.text}}</p>
  </div>
</li>

ちなみに
<style scoped lang="scss">
scopedはコンポーネントごとにcssを切り分けてくれる属性です。

再度ビルド&デプロイ

$ npm run build
$ firebase deploy

完成!
スクリーンショット 2018-10-12 19.09.26.png

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away