FIrebaseとVue.jsを利用した簡易掲示板アプリ

Firebaseを試してみたいと思いたち、Vue.jsを使って簡易的な掲示板アプリを作ってみました。
サンプルのため機能は限定的ですが、ソーシャルゲームのマルチ募集掲示板ぐらいには使えるかもしれません。
CloudFunctionの初回起動が遅いので、実務ではポーリング等で定期的に起こす必要があるでしょう。
こんな感じです。
実装について
構成要素
- Firebase Firestore
- Firebase Functions
- Vue
- Vue-Router
ソースコード抜粋
Firebaseを初期化する部分
src/App.vue
1 2 3 4 5 |
import firebase from 'firebase'; import config from '@/config/dev.config'; firebase.initializeApp(config.firebase); |
スレッドを作成する部分
Firebase FunctionをHTTP経由で呼び出すだけです。
Components/Main.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
export default({ methods { createThreadExec() { this.loading = true; axios.post(config.endpoints.createThread, this.newThread) .then(() => { this.newThreadInput = false; this.newThread.name = ''; this.newThread.comment = ''; this.refresh(); }).catch((e) => { this.displayError(e); }); }, }, }); |
スレッドの一覧を取得する部分
最近更新があったスレッド100件を取得するようにしています。
src/Components/Main.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
export default({ methods { refresh() { const db = firebase.firestore(); db.collection("threads") .orderBy("updateTime", "desc") .limit(100).get().then((querySnapshots) => { this.threads = []; querySnapshots.forEach((doc) => { this.threads.push(doc.data()); }); this.loading = false; }).catch((e) => { this.displayError(e); }); }, } }); |
コメントの一覧を取得し、subscribeを開始する部分
最新1000件のコメントを取得し、その後、コメントに更新があったときに通知されるようsubscribeを登録します。
Firestoreの便利なところは、全てのキーに対して自動的にインデックスが作成されるところですね。
Components/Comments.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
export default({ methods { refresh() { const db = firebase.firestore(); db.collection("comments").doc(this.threadId).collection("comments") .orderBy("updateTime", "desc").limit(1000) .get().then((querySnapshot) => { let commentNumber = this.thread.count; this.comments = []; querySnapshot.forEach((doc) => { this.comments.push(doc.data()); }); }).catch((e) => { this.displayError(e); }); this.unsubscribe(); this.unsubscribe = db.collection("comments").doc(this.threadId).collection("comments") .onSnapshot((snapshot) => { snapshot.docChanges.forEach((change) => { if (change.type === "added") { this.comments.unshift(change.doc.data()); } }); }); }, } }); |
コメントを投稿する部分
スレッド作成同様、Firebase FunctionをHTTP経由で呼び出すだけです。
Components/Comments.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
export default({ methods { writeComment() { this.newComment.threadId = this.threadId; axios.post(config.endpoints.addComment, this.newComment) .then(() => { this.newComment.comment = ''; }) .catch((e) => { this.displayError(e); }) }, }, }); |
Cloud Functions
Functionは2つです。
- AddComment
コメントを投稿するFunctionですコメント投稿時に、スレッドのコメント件数をインクリメントするようにしています。
また、スレッドのupdateTimeを更新することにより、最新のコメントがあったスレッドが上位に表示されるようにしています。 - CreateThread
スレッドを作成するFunctionです。
functions/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
const functions = require('firebase-functions'); const admin = require('firebase-admin'); const cors = require('cors')({origin: true}); admin.initializeApp(functions.config().firebase); exports.AddComment = functions.https.onRequest((req, res) => { cors(req, res, () => { const threadId = req.body.threadId; const comment = req.body.comment; const username = req.body.username; const dateTime = Date.now(); admin.firestore().collection('comments').doc(threadId).collection('comments') .add({ comment: comment, username: username, updateTime: dateTime, }).catch((e) => { console.error(e) }); const threadRef = admin.firestore().collection('threads').doc(threadId); threadRef.get().then((t) => { return threadRef.update({ updateTime: dateTime, count: t.data().count + 1, }).catch((e) => { console.error(e) }); }).catch((e) => { console.error(e) }); res.send({result: 'Success!'}); }); }); exports.CreateThread = functions.https.onRequest((req, res) => { cors(req, res, () => { const name = req.body.name; const comment = req.body.comment; const username = req.body.username; admin.firestore().collection('threads') .add({ name: name, comment: comment, username: username, updateTime: Date.now(), count: 0, }).catch((e) => { console.error(e) }); res.send({result: 'Success!'}); }); }); |