はじめに
すいません、最短は煽りですw
簡単な連絡帳みたいなものを作るサンプルを通して、Vue と Firebase / Firestore の組み合わせの開発コストが低いかを紹介したいと思います。
最初は、アクセス制御をかけずに作成し、次に Firebase の auth を使って認証をかけてみます。
最終形を以下でホスティングしてあります。適当にサインアップして試してみてもらってかまいません。
ロジックに集中するために、デザインはほぼあてていません。見た目悪いのは気にしないでください。
準備
-
Node.js と npm をインストールしてください。
https://nodejs.org/en/
この記事は、8.10.0 LTS で検証しています。 -
vue-cli をインストールしてください。
$ npm i vue-cli -g
Firebase / Firestore をセッティング
公式ドキュメントにのっとればプロジェクトのセットアップまでは簡単です。
Authentication のログイン方法で、メール/パスワードを有効にします。
データベースを Firestore を選択して、ルールをとりあえずテストモードにしておきます。
- Firebase CLI をインストールしてください。
$ npm install -g firebase-tools
- Firebase のアカウントと紐付けてください。
$ firebase login
Vue アプリを作成する
vue init webpack <フォルダ名>
いくつか選択肢が出て答えを求められます。下のように答えたとして話をすすめます。
? Project name 適当
? Project description A Vue.js project
? Author 内緒 <内緒>
? 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? (recommended) npm
firebase モジュールをインストールします。
cd <フォルダ名>
npm i firebase --save
CRUD 画面
このコンポーネントは、認証有り/無しで共通です。
<template>
<div>
<table style="border:1px #808080 solid" v-for="( doc, i ) in docs" :key="i">
<tr v-for="( v, k ) in doc.data()" :key="k"><td>{{ k }}</td><td>{{ v }}</td></tr>
<tr><td><button @click="edit( doc )">編集</button></td><td><button @click="remove( doc )">削除</button></td></tr>
</table>
<hr>
<p v-if="id"><input readonly v-model="id" />を編集中<button @click="id=''">中止</button></p>
<p v-if="!id">新規登録</p>
<div v-for="( v, k ) in draft" :key="k">
<label>{{ k }}</label><input v-model="draft[ k ]" />
</div>
<button @click="submit">登録</button>
</div>
</template>
<script>
import firebase from 'firebase'
import 'firebase/firestore'
export default {
methods: {
edit( p ) {
this.draft = p.data()
this.id = p.id
}
, remove( p ) {
this.col.doc( p.id ).delete().catch( e => alert( e ) )
}
, submit() {
if ( this.id ) {
this.col.doc( this.id ).set( this.draft ).catch( e => alert( e ) )
} else {
this.col.add( this.draft ).catch( e => alert( e ) )
}
}
}
, data() {
return {
col : firebase.firestore().collection( "clients" )
, id : ''
, draft : { 名前: '', 携帯: '', メール: '' }
, docs : []
}
}
, created() {
this.unsubscribe = this.col.onSnapshot( p => this.docs = p.docs )
}
, beforeDestroy() {
this.unsubscribe()
}
}
</script>
認証無し
import firebase from 'firebase'
firebase.initializeApp(
{ apiKey : 'ここには'
, authDomain : '自分の'
, databaseURL : 'やつを'
, projectId : 'はりつけて'
, storageBucket : 'ください'
, messagingSenderId : 'ね!'
}
)
import Vue from 'vue'
Vue.config.productionTip = false
import Main from '@/components/Main'
new Vue(
{ el: '#app'
, template: '<Main />'
, components: { Main }
}
)
わずかこれだけのソースで書けてしまします。
npm run dev
で走らせてみます。
認証あり
認証を入れると、ちょっと複雑になります。
認証画面と CRUD 画面の遷移が発生するので、vue-router を使っています。また、ログイン情報をグローバルに使いたいので、Vuex を使っています。以下のコマンドでインストールしてください。
npm i vue-router --save
npm i vuex --save
import firebase from 'firebase'
firebase.initializeApp(
{ apiKey : 'ここには'
, authDomain : '自分の'
, databaseURL : 'やつを'
, projectId : 'はりつけて'
, storageBucket : 'ください'
, messagingSenderId : 'ね!'
}
)
import Vue from 'vue'
Vue.config.productionTip = false
import Router from 'vue-router'
Vue.use( Router )
import Vuex from 'vuex'
Vue.use( Vuex )
const
Login = {
template: `
<div>
<label>e-mail__:</label><input type="email" v-model="email" /> <br />
<label>password:</label><input type="password" v-model="password" /> <br />
<button type="button" @click="login"> Login</button> <br />
<label>nickname:</label><input type="text" v-model="nickname" /> <br />
<button type="button" @click="signup"> Signup</button> <br />
</div>
`
, data() {
return {
email : ''
, password: ''
, nickname: ''
}
}
, methods: {
login() {
firebase.auth().signInWithEmailAndPassword( this.email, this.password ).then(
p => this.$router.push( this.$route.query.redirect ? this.$route.query.redirect : '/' )
).catch( e => alert( e ) )
}
, signup() {
if ( this.nickname ) {
firebase.auth().createUserWithEmailAndPassword( this.email, this.password ).then(
user => user.updateProfile( { displayName: this.nickname } )
).then(
() => {
this.$store.commit( 'user', firebase.auth().currentUser )
this.$router.push( this.$route.query.redirect ? this.$route.query.redirect : '/' )
}
).catch( e => alert( e ) )
}
}
}
}
import Main from '@/components/Main'
const
App = {
template: `
<div>
<template v-if="$store.state.user">
<span>You're {{ $store.state.user.displayName }}</span>
<button @click="$router.push( '/login' )">Logout</button>
<hr>
</template>
<Main />
</div>
`
, components: { Main }
}
let app
firebase.auth().onAuthStateChanged(
p => {
if ( app ) {
app.$store.commit( 'user', p )
} else {
const
router = new Router(
{ routes:
[ { path: '/' , component: App }
, { path: '/login' , component: Login }
, { path: '/*' , component: { template: '<div>NotFound</div>' } }
]
}
)
router.beforeEach(
async ( to, from, next ) => {
if ( firebase.auth().currentUser ) {
if ( to.path == '/login' ) await firebase.auth().signOut()
next()
} else {
if ( to.path == '/' ) {
next( { path: 'login', query: { redirect: to.path } } )
} else {
next()
}
}
}
)
app = new Vue(
{ el : '#app'
, store : new Vuex.Store(
{ state : { user: p }
, mutations : { user: ( state, payload ) => state.user = payload }
}
)
, router
, template: `<router-view />`
}
)
}
}
)
おわりに
Vue.js を使うとビジネスロジックと認証のロジックをソース上で綺麗にわけることができます。
ほんとにいい時代になりました。
それではー