はじめてのVue JS 2 & Firebase

## Introduction :fire:
この記事では**Vue JS**と**Firebase**の基本的な使用方法を簡単なチャットアプリの作成を通して紹介します！また、環境構築は**Vue CLI**を使用します。またFirebaseは**Cloud Firebaseβ**のほうを使用しました。
> できたもの：https://chat-slush.firebaseapp.com/#/

![firebase.mov.gif](https://qiita-image-store.s3.amazonaws.com/0/266140/8b7eae5f-80f8-39c4-bc67-a917977c992b.gif)
## 1. Vue CLIによる環境構築
##### Vue CLIとは？
>Vue.jsを使ったアプリケーション開発を支援するためのコマンドラインインターフェイス。設定ファイルを自動的に作成して環境構築の手助けをしてくれる。

##### 何はともあれ **vue init webpack [project name]**
```bash
$ vue init webpack chat-app

? Project name chat-test
? Project description A Vue.js project
? Author funabashi800
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? No
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? NPM
```
#### 開発環境
```json
"dependencies": {
    "firebase": "^5.5.3",
    "moment": "^2.22.2",
    "vue": "^2.5.2",
    "vue-chat-scroll": "^1.3.3",
    "vue-router": "^3.0.1"
  }
```
以上の**dependencies**は以下のようにインストールすると勝手に**package.json**に追加されます

```
$ npm install firebase --save
```

## 2. Firebaseにメッセージをadd
まずはじめにFirebaseのconfigファイルを作成。自分の場合は**/src/firebase/init.js**につくりました。

```javascript:init.js
import firebase from 'firebase'
import 'firebase/firestore'

// Initialize Firebase
var config = {
    apiKey: "xxxxxxxxx"
    databaseURL: "xxxxxxxxx",
    projectId: "xxxxxxxxx",
    storageBucket: "xxxxxxxxx",
    messagingSenderId: "xxxxxxxxx"
  };
  const firebaseApp = firebase.initializeApp(config);
  firebaseApp.firestore().settings({ timestampsInSnapshots: true})

// export firestore database
export default firebaseApp.firestore()
```
メッセージは**textarea**から入力し**v-model**で**data**の**message**とバインドされています。また**@click**(**v-on:click**)によってイベントハンドラして**AddMessage**メソッドを設定します。**AddMessage**内では上記の**init.js**からfirebaseを扱うためのインスタンスをインポートします。

```vuejs:Chat.vue
<template> 
    <div class="new-message">
        <form class="ui reply form">
            <div class="field">
            <textarea v-model="message"></textarea>
            </div>
            <div class="ui primary submit labeled icon button" @click="AddMessage">
            <i class="icon edit"></i> Add Comment
            </div>
        </form>
    </div>
</template>
<script>
import db from '@/firebase/init'
export default {
  	name: 'Newmessage',
	props: ["name"],
	data () {
		return {
		message: null
		}
	},
  	methods: {
		AddMessage(){
			if(this.message){
				db.collection('messages').add({
					username: this.name,
					message: this.message,
					date: Date.now()
				})
				this.message = null
			}
		}
  	} 
}
```

以上のメソッドが実行されるとFirebase側は以下のようになります。また、これらのコレクションやフィールドは事前に設定する必要はないです:sunny:

![スクリーンショット 2018-10-07 16.40.39.png](https://qiita-image-store.s3.amazonaws.com/0/266140/1e8042c7-b300-fdba-bcc3-6a9d16b70921.png)

## 2. Firebaseのデータを表示
#### vue-chat-scroll
[vue-chat-scroll](https://github.com/theomessin/vue-chat-scroll)というVue JS 2のプラグインを使ってメッセージの自動スクロールを実装しました。

#### onSnapshot
Firebaseからのデータの取得は**onSnapshot**メソッドを使ってリアルタイムでメッセージを更新しました。
>参考：[Cloud Firestore でリアルタイム アップデートを入手する](https://firebase.google.com/docs/firestore/query-data/listen?hl=ja)

#### Moment.js
またタイムスタンプの表示は[Moment.js](https://momentjs.com/)というライブラリを使用しました。

```vue:ShowMessage.vue
<template>
<div class="chat">
	<div class="ui comments">
		<div class="msg" v-chat-scroll>
			<div v-for="message in messages" :key="message.id">
				<div class="comment">
					<a class="avatar">
						<img src="../assets/firebase.png">
					</a>
					<div class="content">
						<a class="author">{{ message.username }}</a>
						<div class="metadata">
							<div class="date">{{ message.date }}</div>
						</div>
						<div class="text">
							<p>{{ message.message }}</p>
						</div>
					</div>
				</div>
			</div>
		</div>
		<Newmessage :name="name"></Newmessage>
	</div>
</div>
</template>

<script>
import Newmessage from '@/components/Newmessage'
import moment from 'moment'
import db from '@/firebase/init'
import VueChatScroll from 'vue-chat-scroll'
import Vue from 'vue'
Vue.use(VueChatScroll)
export default {
	name: 'Chat',
	props: ['name'],
	data () {
		return {
		messages: []
		
		}
	},
	components: {
		Newmessage
	},
	created() {
		let msg = db.collection('messages').orderBy('date')
		msg.onSnapshot(snapshot => {
			snapshot.docChanges().forEach(change => {
				if(change.type == 'added'){
					let doc = change.doc
					this.messages.push({
					id: doc.data().id,
					message: doc.data().message,
					username: doc.data().username,
					date: moment(doc.data().date).format("MM DD HH:mm")
					})
				}
			})
		})
	}
}
</script>
```

## 3. Vue Router
**Vue Router**というコンポーネントとURLを紐付けてコンテンツを生成し、SPAを構築するためのVue JSの拡張ライブラリを使用して、以上の**NewMessage.vue**をURLと紐づけます。ちなみに**Vue Router**は`vue init webpack`したときにインストールします。**Vue Rotuer**の設定は**/src/router/index.js**に書きます。

```javascript:index.js
import Vue from 'vue'
import Router from 'vue-router'
import Welcome from '@/components/Welcome'
import Chat from '@/components/Chat';

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Welcome',
      component: Welcome
    },
    {
      path: '/chat',
      name: 'Chat',
      component: Chat,
      props: true
    }
  ]
})
```
ちなみにpropsはWelcomeページからusernameを受け取るに使用していますが、割愛します。Welcomeページからusernameの受け渡しは`this.$router.push({name: "Chat", params: {name: this.username}})`こんな感じでわたします。

## 4. Firebase Hosting
`firebase deploy`する前に`npm run build`し、公開するフォルダは"**dist**"と命名してください。（npmとの互換性）

```
$ firebase init

     🔥🔥🔥🔥🔥🔥🔥🔥 🔥🔥🔥🔥 🔥🔥🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥🔥🔥 🔥🔥🔥🔥🔥🔥🔥🔥     🔥🔥🔥     🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥🔥🔥
     🔥🔥        🔥🔥  🔥🔥     🔥🔥 🔥🔥       🔥🔥     🔥🔥  🔥🔥   🔥🔥  🔥🔥       🔥🔥
     🔥🔥🔥🔥🔥🔥    🔥🔥  🔥🔥🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥   🔥🔥🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥
     🔥🔥        🔥🔥  🔥🔥    🔥🔥  🔥🔥       🔥🔥     🔥🔥 🔥🔥     🔥🔥       🔥🔥 🔥🔥
     🔥🔥       🔥🔥🔥🔥 🔥🔥     🔥🔥 🔥🔥🔥🔥🔥🔥🔥🔥 🔥🔥🔥🔥🔥🔥🔥🔥  🔥🔥     🔥🔥  🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥🔥🔥

? Which Firebase CLI features do you want to setup for this folder? Press Space
to select features, then Enter to confirm your choices. (Press <space> to select
)
 ◯ Database: Deploy Firebase Realtime Database Rules
❯◯ Firestore: Deploy rules and create indexes for Firestore
 ◯ Functions: Configure and deploy Cloud Functions
❯◯ Hosting: Configure and deploy Firebase Hosting sites
 ◯ Storage: Deploy Cloud Storage security rules

=== Project Setup
? Select a default Firebase project for this directory: [your project in firebase]
=== Firestore Setup
? What file should be used for Firestore Rules? firestore.rules
? What file should be used for Firestore indexes? firestore.indexes.json
=== Hosting Setup
? What do you want to use as your public directory? dist

$ npm run build
$ firebase deploy
```

## 最後に
以上、流行りの**Firebase**と**Vue**入門でした！コードの詳細はGithubを参照ください！
> https://github.com/funabashi800/slush-chat