Vue.js × Vuex × Firebase Auth まとめ

Vue.jsとVuexとFirebase Authでログイン認証のテンプレをまとめておきます。
Vue Routerも入れてます。
今回紹介するのは、メールアドレス認証です。
詳しい解説は、少し飛ばします。

## Vue.jsとは
Vue.jsはUI構築のためのJavaScriptプログレッシブフレームワークのこと
[Vue.js公式サイト](https://jp.vuejs.org/)

## Vuexとは
Vue.jsアプリの状態管理をするためのライブラリのこと
[Vuexとは](https://vuex.vuejs.org/ja/)

## Firebaseとは
Googleが提供しているモバイルおよびWebアプリケーションのバックエンドサービスのこと
[Firebase](https://firebase.google.com/)

## 手順
### Node.jsのインストール
Node.jsの公式サイトにアクセスし、推奨版をインストールします。
すでにNode.jsをインストールしている場合は、この作業は飛ばします。
[Node.js公式](https://nodejs.org/ja/)

### VueCLIのインストール
ターミナルを開き、VueCLIをグローバルインストールします。
すでにVueCLIをインストールしている場合は、この作業は飛ばします。

```terminal:ターミナル
npm install -g @vue/cli
```

### パスを通す
.bash_profileを開き、node_moduleにパスを通します。
なお、Users/usernameのusernameを自分のユーザ名に変更してください。
すでにパスを通している場合は、この作業は飛ばします。

```terminal:ターミナル
open ~/.bash_profile
```

```text:.bash_profile
export PATH="$PATH:/Users/username/.npm-global/bin"
```

```terminal:ターミナル
source ~/.bash_profile
```

### Vue.jsプロジェクトの作成
vue createコマンドでVue.jsプロジェクトを作成します。

```terminal:ターミナル
vue create vue-vuex-fire-auth
```

下記のような表示が出るので、defaultを選択してEnterを押下。

```terminal:ターミナル
Vue CLI v4.4.1
? Please pick a preset: (Use arrow keys)
❯ default (babel, eslint) 
  Manually select features 
```

### Vuexのインストール
状態管理のライブラリ「Vuex」を入れます。

```terminal:ターミナル
npm install vuex --save
```

### Vue Routerのインストール
ルーティングのライブラリ「Vue Router」を入れます。

```terminal:ターミナル
npm install vue-router
```

### firebaseのインストール
バックエンドを担当するfirebaseとの通信をするためのライブラリ「firebase」を入れます。

```terminal:ターミナル
npm install firebase --save
```

### ディレクトリ整理
Vue.jsのディレクトリを整理します。

```
- vue-vuex-fire-auth
    - node_modules
    - public
        - js             // 追加
        - styles         // 追加
        - favicon.ico
        - index.html
    - src
        - assets
            - images     // 追加
        - components
        - pages          // 追加
            - Home.vue   // 追加
            - Login.vue  // 追加
        - App.vue
        - firebase.js    // 追加
        - main.js
        - router.js      // 追加
        - store.js       // 追加
    - babel.config.js
    - package-lock.json
    - package.json
    - README.md
```

### main.jsの記述
main.jsの記述をrouter.jsとstore.jsとfirebase.jsを読み込むように変えます。

```js:main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from "./store";
import './firebase';

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: h => h(App),
}).$mount('#app');
```

### Vuexの記述
store.jsにVuexの記述をしていきます。

```js:store.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    user: null,
  },
  getters: {
    user(state){
      return state.user;
    },
  },
  actions: {
  },
  mutations: {
    updateUser(state, { user }) {
      Vue.set(state, "user", user);
    },
  }
});
```

### Vue Routerの記述
router.jsにVue Routerの記述をしていきます。

```js:router.js
import Vue from "vue";
import Router from "vue-router";
import Home from "./pages/Home";
import Signin from "./pages/Signin";

Vue.use(Router);

let router = new Router({
  mode: "history",
  routes: [
    {
      path: "/",
      name: 'Home',
      component: Home,
    },
    {
      path: "/signin",
      name: 'Signin',
      component: Signin
    },
  ]
});

export default router
```

App.vueの記述をVue Routerを使う形に変えます。

```vue:App.vue
<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
};
</script>
```

### Firebaseプロジェクトの作成

- 1. Googleのアカウントを作成し、Firebaseのサイトへアクセスします。
- 2. コンソールへ移動
- 3. コンソール画面で新規プロジェクトを作成
- 4. プロジェクト名を入力
- 5. アナリティクスの有効有無を選択する
- 6. プロジェクトの作成が完了

<font color="#CC011B"><strong>詳しいやり方は、[こちら](https://korenarawakaru.com/firebase/firebase-start) を参考にしてください。</strong></font>

### Firebaseウェブアプリの追加
Firebaseプロジェクトにウェブアプリを追加します。

ウェブを追加をクリックします。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473780/ab67b5b6-e34e-5e67-1696-f9f16cd35e28.png)
好きな名前でアプリを登録します。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473780/74836326-29eb-f27f-e40a-9017c2781c9d.png)
ここのapiKeyなどはあとで使います。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473780/11c8c102-f033-f86c-cddd-bcaa678aee42.png)

### Firebase Authのメールアドレス認証を許可する
Firebase Authのメールアドレス認証を有効にします。

サイドバーのAuthenticationをクリックします。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473780/551c3741-44a5-0cd3-c16e-3b248a613fdd.png)
Sign-in methodをクリッします。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473780/24c2e574-a958-8f90-0a27-b6524a87a023.png)
メール/パスワードをクリック
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473780/4baf8aa2-1259-ffa5-f806-7ecf26755341.png)
有効にするにチェックして、保存をクリックします。
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473780/06aec7d2-fe0b-3296-4e0a-a50956664ca6.png)
テスト用にユーザーを追加します。
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473780/3cf6a7fa-8f70-342a-c4e3-5ee01bd1ff72.png)

### firebase.jsの記述
firebase.jsの記述をしていきます。
apiKeyなどは、ウェブアプリを追加した時に表示されていたやつです。それを記述してください。
ログインされたら、Vuexのuserにデータを入れてログイン状態を保持します。

```js:firebase.js
import firebase from "firebase/app";
import "@firebase/auth";
import store from "./store";

var firebaseConfig = {
  apiKey: "",
  authDomain: "",
  databaseURL: "",
  projectId: "",
  storageBucket: "",
  messagingSenderId: ""
}
firebase.initializeApp(firebaseConfig);
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION);

firebase.auth().onAuthStateChanged(user => {
  store.commit("updateUser", { user });
});
```

### router.jsの記述の変更
Vuexのuserのデータを確認して、ログイン状態を判断します。
ログインされていない場合は、signinにリダイレクトされます。

```js:router.js
import Vue from "vue";
import Router from "vue-router";
import Home from "./pages/Home";
import Signin from "./pages/Signin";
import store from "./store";

Vue.use(Router);

let router = new Router({
  mode: "history",
  routes: [
    {
      path: '*',
      redirect: 'signin'
    },
    {
      path: "/",
      name: 'Home',
      component: Home,
      meta: { requiresAuth: true }
    },
    {
      path: "/signin",
      name: 'Signin',
      component: Signin
    },
  ]
});

router.beforeEach((to, from, next) => {
  const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
  if (requiresAuth) {
    if (!store.state.user) {
      next({
        path: '/signin',
        query: { redirect: to.fullPath }
      })
    } else {
      next()
    }
  } else {
    next()
  }
});

export default router
```

### Signin.vueとHome.vueの記述

```vue:Signin.vue
<template>
  <div>
    <input type="email" placeholder="メールアドレス" v-model="email">
    <input type="password" placeholder="パスワード" v-model="password">
    <button type="submit" v-on:click="signIn">ログイン</button>
  </div>
</template>

<script>
import firebase from 'firebase';
import "firebase/auth";
export default {
  name: 'signin',
  data () {
    return {
      email: '',
      password: ''
    }
  },
  computed: {
    user(){
      return this.$store.getters['user'];
    },
  },
  watch: {
    user: function(changedUser) {
      if (changedUser) {
        this.$router.replace('/');
      }
    },
  },
  methods: {
    // ログイン処理
    signIn: function () {
      firebase.auth().signInWithEmailAndPassword(this.email, this.password).then(user => {
        console.log(user);
      }).catch(error => {
        alert(error.message)
      })
    },
  }
}
</script>
```

```vue:Home.vue
<template>
  <div>
    <p>{{ user.email }}</p>
    <router-link to="/signin" v-on:click.native="signOut">ログアウト</router-link>
  </div>
</template>

<script>
import firebase from 'firebase';
export default {
  computed: {
    user(){
      return this.$store.getters['user'];
    },
  },
  methods: {
    // ログアウト処理
    signOut() {
      firebase.auth().signOut();
      this.$router.push('/signin');
    }
  }
}
</script>
```

## 最終的なコード
最終的なコードはこちらにまとめました↓
[vue-vuex-fire-auth | GitHub](https://github.com/engineerhikaru/vue-vuex-fire-auth)

## まとめ
この記事が良いと思った方は、LGTMをしていただければ嬉しいです！
フォローも是非お願い致します(^^)