0. 下準備
-
Firebaseプロジェクトの作成
https://firebase.google.com/ -
firebaseツールのインストール(global)
$ npm install -g firebase-tools
- npxのインストール(global)
$ npm install -g npx
1. Nuxt.jsのインストールと起動確認
- Nuxt.jsのインストール
npx create-nuxt-app firenuxt
# 設定内容
# > Generating Nuxt.js project in /Users/keisuke/workspace/nuxtjs/firenuxt
# ? Project name firenuxt
# ? Project description My marvelous Nuxt.js project
# ? Use a custom server framework none
# ? Use a custom UI framework none
# ? Choose rendering mode Universal
# ? Use axios module yes
# ? Use eslint no
# ? Use prettier no
# ? Author name keisuke shingaki
# ? Choose a package manager npm
- 開発サーバーの起動
$ cd firenuxt
$ npm run dev
# http://localhost:3000で表示が確認できる
1. Firebaseのセットアップ
$ 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. Hosting: Configure and deploy Firebase Hosting sites
# ? Select a default Firebase project for this directory: firenuxt-30550 (firenuxt)
# ? What do you want to use as your public directory? public
# ? Configure as a single-page app (rewrite all urls to /index.html)? No
- 下記のような構成になる
.
├── .editorconfig
├── .firebaserc # firebaseのプロジェクトファイル
├── .git
├── .gitignore
├── .nuxt
├── README.md
├── assets
├── components
├── firebase.json # firebaseの設定ファイル
├── layouts
├── middleware
├── node_modules
├── nuxt.config.js
├── package-lock.json
├── package.json
├── pages
├── plugins
├── public
├── static
└── store
2. Nuxt.jsのビルドとFirebase Hostingへのデプロイ
- Nuxt.jsのビルド
$ npm run generate
- firebaseのpublicルートの変更(firebase.json)
firebase.json
{
"hosting": {
- "public": "public",
+ "public": "dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}
- デプロイ
$ firebase deploy
2. Firebase Authenticationで認証
2.1 Loginテンプレートを作成
pages/index.vue
<template>
<section class="container">
<div>
<!-- 新規登録フォーム -->
<section>
<h5>新規登録</h5>
<p><input type="text" placeholder="メールアドレス"></p>
<p><input type="password" placeholder="パスワード"></p>
<div class="links">
<button>新規登録</button>
</div>
</section>
<!-- ログインフォーム -->
<section>
<h5>ログイン</h5>
<p><input type="text" placeholder="メールアドレス"></p>
<p><input type="password" placeholder="パスワード"></p>
<div class="links">
<button>ログイン</button>
</div>
</section>
<!-- マイページ -->
<section>
<h5>ログイン中です</h5>
<!-- ログイン中ユーザーのメールアドレスを表示 -->
<p>メールアドレス:</p>
<div class="links">
<button>ログアウト</button>
</div>
<div>
<ul><li>めっせーじ</li></ul>
</div>
<div class="links">
<p><input type="text" placeholder="メッセージ"></p>
<button>メッセージ追加</button>
</div>
</section>
</div>
</section>
</template>
<style>
.container {
padding: 100px;
}
</style>
2.2 Firebase Authenticationの設定
- ライブラリのインストール
$ npm install firebase
- 設定ファイルを追加
コンソールから情報を確認
plugins/firebase.js
import firebase from 'firebase'
if (!firebase.apps.length) {
firebase.initializeApp({
apiKey: "xxxxx",
authDomain: "xxxxx",
databaseURL: "xxxxx",
projectId: "xxxxx",
storageBucket: "xxxxx",
messagingSenderId: "xxxxx"
})
}
export default firebase
- FirebaseコンソールでAuthenticatioでメール/パスワードの認証を有効にする
2.3 Firebase Authenticationで新規登録
- APIアクセス部分を作成
api/UserAPI.js
import firebase from '@/plugins/firebase'
export default class UserAPI {
/**
* メールアドレスとパスワードで新規ユーザー登録を実施します。
* @param {string} mailAddress
* @param {string} password
*/
static regist(mailAddress, password) {
return firebase.auth().createUserWithEmailAndPassword(mailAddress, password);
}
/**
* メールアドレスとパスワードでログインを実施します。
* @param {string} mailAddress
* @param {string} password
*/
static login(mailAddress, password) {
return firebase.auth().signInWithEmailAndPassword(mailAddress, password);
}
/**
* ログアウトします。
*/
static logout() {
return firebase.auth().signOut();
}
/**
* ユーザー情報を取得します。
*/
static getUser() {
return firebase.auth().currentUser;
}
}
- Store部分を作成
store/user.js
// UserAPIのインポート
import UserAPI from "@/api/UserAPI"
export const state = () => ({
isLogin: false,
emailAddress: ""
})
export const mutations = {
// ユーザー情報を設定します。
setEntity(state, user) {
state.emailAddress = user.email;
},
// stateを初期化します。
clear(state) {
state.emailAddress = "";
state.isLogin = false;
},
// ログイン状態を設定します。
setIsLogin(state, isLogin) {
state.isLogin = isLogin;
}
}
export const actions = {
// ユーザー情報を取得します。
load: ({ commit }) => {
var currentUser = UserAPI.getUser();
if (currentUser) {
// ログイン済み
commit('setIsLogin', true);
commit('setEntity', currentUser);
} else {
// 未ログイン
commit('setIsLogin', false);
commit('clear');
}
},
// 新規ユーザー登録を行います。
regist: ({ commit, dispatch }, payload) => {
return UserAPI.regist(payload.mailAddress, payload.password)
.then((res) => {
commit('setIsLogin', true);
dispatch('setEntity', res.user);
})
.catch(function(error) {
commit('setIsLogin', false);
commit('clear');
});
},
// ユーザーログインを行います。
login: ({ commit, dispatch }, payload) => {
return UserAPI.login(payload.mailAddress, payload.password)
.then((res) => {
commit('setIsLogin', true);
dispatch('setEntity', res.user);
})
.catch(function(error) {
commit('setIsLogin', false);
commit('clear');
});
},
// ログアウトを行います。
logout: ({ commit }) => {
return UserAPI.logout()
.then((res) => {
commit('setIsLogin', false);
commit('clear');
})
.catch(function(error) {
console.log(error);
});
},
// 新規ユーザー登録を行います。
setEntity: ({ commit }, user) => {
commit('setEntity', user);
}
}
- viewファイルへ組み込み
pages/index.vue
<template>
<section class="container">
<div>
<!-- 新規登録フォーム -->
<section v-if="!isLogin">
<h5>新規登録</h5>
<p><input type="text" v-model="mailAddress" placeholder="メールアドレス"></p>
<p><input type="password" v-model="password" placeholder="パスワード"></p>
<div class="links">
<button @click="regist()">新規登録</button>
</div>
</section>
<!-- ログインフォーム -->
<section v-if="!isLogin">
<h5>ログイン</h5>
<p><input type="text" v-model="mailAddress" placeholder="メールアドレス"></p>
<p><input type="password" v-model="password" placeholder="パスワード"></p>
<div class="links">
<button @click="login()">ログイン</button>
</div>
</section>
<!-- マイページ -->
<section v-if="isLogin">
<h5>ログイン中です</h5>
<!-- ログイン中ユーザーのメールアドレスを表示 -->
<p>メールアドレス:{{$store.state.user.emailAddress}}</p>
<div class="links">
<button @click="logout()">ログアウト</button>
</div>
</section>
</div>
</section>
</template>
<script>
export default {
data: function(){
return {
mailAddress: '',
password: '',
content: '',
}
},
computed: {
isLogin(){
return this.$store.state.user.isLogin;
}
},
methods: {
init: function() {
this.password = "";
this.mailAddress = "";
this.content = "";
},
regist: function () {
console.log("regist")
this.$store.dispatch('user/regist', {mailAddress:this.mailAddress, password:this.password});
this.init();
},
login: function () {
this.$store.dispatch('user/login', {mailAddress:this.mailAddress, password:this.password});
this.init();
this.getMessages()
},
logout : function() {
this.$store.dispatch('user/logout');
}
},
}
</script>
<style>
.container {
padding: 100px;
}
</style>
3. Firebase Firestoreでデータを保存
3.1 Firestoreの設定
3.2 設定ファイルの編集
plugins/firebase.js
import firebase from 'firebase'
if (!firebase.apps.length) {
firebase.initializeApp({
apiKey: "xxxxx",
authDomain: "xxxxx",
databaseURL: "xxxxx",
projectId: "xxxxx",
storageBucket: "xxxxx",
messagingSenderId: "xxxxx"
})
}
// DB設定を追加
const firestore = firebase.firestore();
const settings = { timestampsInSnapshots: true };
firestore.settings(settings);
export default firebase
- API部分の実装
api/MessageAPI.js
import firebase from '@/plugins/firebase'
export default class MessageAPI {
/**
* メッセージのリストを取得
*/
static getMessages() {
const messagesRef = firebase.firestore().collection('messages')
return messagesRef.orderBy('created', 'desc').get()
}
/**
* メッセージを追加
* @param {string} message
*/
static addMessage(messageContent) {
let message = {
content: messageContent,
created: Date.now()
}
return firebase.firestore().collection('messages').add(message)
}
}
- Store部分を作成
store/message.js
// MessageAPIのインポート
import MessageAPI from "@/api/MessageAPI"
export const state = () => ({
items: []
})
export const mutations = {
setEntity(state, items) {
state.items = items;
},
clear(state) {
state.items = [];
}
}
export const actions = {
load: ({ commit }) => {
return MessageAPI.getMessages()
.then((res) => {
let messages = []
res.forEach(doc => {
let data = {
id: doc.id,
content: doc.data().content
}
messages.push(data)
})
commit('setEntity', messages)
})
.catch(function(error) {
console.log(error)
commit('clear');
});
},
add: ({ commit, dispatch }, payload) => {
return MessageAPI.addMessage(payload.messageContent)
.then((res) => {
dispatch('load');
})
.catch(function(error) {
commit('clear');
});
},
}
- viewファイルへ組み込み
pages/index.vue
<template>
<section class="container">
<div>
<!-- 新規登録フォーム -->
<section v-if="!isLogin">
<h5>新規登録</h5>
<p><input type="text" v-model="mailAddress" placeholder="メールアドレス"></p>
<p><input type="password" v-model="password" placeholder="パスワード"></p>
<div class="links">
<button @click="regist()">新規登録</button>
</div>
</section>
<!-- ログインフォーム -->
<section v-if="!isLogin">
<h5>ログイン</h5>
<p><input type="text" v-model="mailAddress" placeholder="メールアドレス"></p>
<p><input type="password" v-model="password" placeholder="パスワード"></p>
<div class="links">
<button @click="login()">ログイン</button>
</div>
</section>
<!-- マイページ -->
<section v-if="isLogin">
<h5>ログイン中です</h5>
<!-- ログイン中ユーザーのメールアドレスを表示 -->
<p>メールアドレス:{{$store.state.user.emailAddress}}</p>
<div class="links">
<button @click="logout()">ログアウト</button>
</div>
<div>
<ul v-for="(item,index) in $store.state.message.items" :key="index">
<li>{{ item.content }}</li>
</ul>
</div>
<div class="links">
<p><input type="text" v-model="content" placeholder="メッセージ"></p>
<button @click="addMessage()">メッセージ追加</button>
</div>
</section>
</div>
</section>
</template>
<script>
export default {
data: function(){
return {
mailAddress: '',
password: '',
content: '',
}
},
computed: {
isLogin(){
return this.$store.state.user.isLogin;
}
},
methods: {
init: function() {
this.password = "";
this.mailAddress = "";
this.content = "";
},
regist: function () {
console.log("regist")
this.$store.dispatch('user/regist', {mailAddress:this.mailAddress, password:this.password});
this.init();
},
login: function () {
this.$store.dispatch('user/login', {mailAddress:this.mailAddress, password:this.password});
this.init();
this.getMessages()
},
getMessages: function() {
this.$store.dispatch('message/load');
},
addMessage: function() {
this.$store.dispatch('message/add', { messageContent: this.content });
this.init();
},
logout : function() {
this.$store.dispatch('user/logout');
}
},
}
</script>
<style>
.container {
padding: 100px;
}
</style>
- 実装画面
参考
Nuxt.jsとFirebaseでWebアプリケーション開発 - Speaker Deck
https://speakerdeck.com/takec24/nuxt-dot-jstofirebasedewebapurikesiyonkai-fa?slide=20
Firebaseの各機能を3行で説明する - Qiita
https://qiita.com/shibukk/items/4a015c5b3296563ac19d
Nuxt v2とFirebase(CloudFirestore)でPWA対応Webアプリ開発 - Qiita
https://qiita.com/_takeshi_24/items/3ee051e1db1b3e8da106