Help us understand the problem. What is going on with this article?

Nuxt(SPA)+Firebaseでログイン処理を実装する

More than 1 year has passed since last update.

はじめに

今回は、NuxtとFirebaseを使って認証処理を実装した時の記録を記事として残しておきます。
※NuxtはTypescriptで実装するようにしています。

作業環境

OS: Windows 10 Pro
Node: 12.1.0
npm: 6.9.0 
Yarn: 1.15.2

Nuxtを選択する

NuxtはVueの公式ガイドラインに沿って強力なアーキテクチャを提供するように設計されたフレームワークとのことです。
コーディングの統一性が高い分、大規模なプロジェクトでも手軽に組めてしまいます。
Vue単体で一からプロジェクトを構築するのも良いのですが、最初からある程度規約が整っているNuxtで開発を進めると複数の開発者がいる場合なんかは作業効率が跳ね上がりますね。
逆に、既存のプロジェクトに対して一部Vueのアプリを取り入れるみたいな時はNuxtを使わずにVue単体で構築するのが吉でしょう。

VueCLI3でもよくない?

Vueのプロジェクトを構築するにあたり、VueCLI3もしくはNuxtのどちらかで作り始めるという話がよくあります。

私の場合、個人でも開発できてしまうような小規模なものにはVueCLI3を採用したりしています。
VueCLI3を使用すれば、プロジェクト作成時にVueRouter、Vuex、TypeScript等を選択すれば十分に満足のできるテンプレートが出来上がりますからね。

ページ数の多さ、データの状態管理の多さ、複数の開発者といったような場合はNuxtを採用したりします。
Nuxtは規約重視なフレームワークになっておりますので、実装の統一性という面から採用します。
また、SSRを取り入れたい時はNuxtの出番ですね。
Vue単体でSSRやる場合はけっこう設定が面倒だったりします。(VueでSSR
さらに、Nuxtはサーバーミドルウェアを構築できたりします。
外部サーバを用意せずにJavascriptでAPIを用意したい時なんかはNuxtだけで実現できてしまいます。

Firebaseを選択する

Firebaseとは、言わずと知れたGoogleが提供しているWebアプリケーションのバックエンドサービスですね。
ドキュメントも分かりやすく、流行りのサーバレスアーキテクチャを学習コストほぼなしで実現できちゃいます。
サーバレスアーキテクチャってのはバックエンド系は任せちゃうやつです。
例えば、Web開発を行っていくうえで、NodeJSやPHP,Pythonを使ってDB操作や認証処理とかをバックエンド側として実装したりしますね。(DBを自前で用意してModel作って、、、リクエストされたpayloadからトークン発行して、、、などのアレです。)
アレをやらなくて済みます。

準備

Firebaseを始めてみる

まずはGoogleのアカウントを用意しましょう。
用意ができたら、Firebase Consoleへアクセスします。
1.png
上記の画面を確認したら、プロジェクトを作成を押します。
2.png
上記の画面では、適当なプロジェクト名を入力して規約同意にチェックして続行を押します。
3.png
上記の画面は、Googleアナリティクスを有効にするかどうかです。チェックして続行を押します。
4.png
先ほどの画面で、Googleアナリティクスを有効にチェックをしました。
そのため、アナリティクス対象の地域を選択したり、分析データの共有同意を求められます。
チェックしてプロジェクトを作成ボタンを押します。
5.png
少し時間が経つとプロジェクトが作成されます。続行を押します。
6.png
無事にプロジェクトの作成が終わりました。
Firebase Consoleからいつでも入れます。

※Googleアナリティクス
プロジェクト作成中にあったGoogleアナリティクスについてですが、
有効にしておくとアプリの使用状況とユーザーエンゲージメントについて分析できたりします。
ユーザの行動を把握してアプリのマーケティング方法の決定を決めるのに利用したり出来るようですね。
私はマーケティング経験も知識もないので使い道は良く知りませんが。。

Nuxtを始めてみる

$ npx create-nuxt-app <project-name>
# もしくは
$ yarn create nuxt-app <project-name>

公式を見ると上のコマンドで始められるとあります。
ローカルの環境にnpxコマンドもしくはyarn コマンドが必要みたいですね。
npxnpmyarnは Node.js のパッケージを管理するためのManagerツールですね。
例えば聞き慣れたNode系パッケージのexpressなんかをプロジェクト内に手軽にインストールできたりします。

npmとnpxは何が違うのか

npmnpxもNodeパッケージをインストールする時に使用します。
ですが、インストールしたパッケージの実行方法が異なります。

npmグローバルにパッケージをインストールした時はパスの設定が自動的に行われるのでコマンドの実行が行えますが、ローカルにインストールした場合はコマンドでの実行がやや面倒くさくなります。
ローカルの場合は、./node_modules/.bin/xxxもしくは$(npm bin)/xxxとコマンドが配置されている場所を指定してあげる必要があるんです。

ですが、npxの場合はグローバルだろうとローカルだろうと関係なくコマンド実行できてしまうんです。
npx xxxで実行できます。
また./node_modules/.bin/xxxのようにパッケージを実行するためには当然、node_modulesの中にパッケージがインストールされている必要がありますよね。
npxコマンド場合はパッケージがインストールされていなくても実行できてしまいます。
実行する前に、一時的に該当パッケージがインストールされるようですね。

一例を実行してみたので下記ご参照ください。

PS C:\Users\user\Desktop> npm inatall envinfo
# envinfoがあるので実行できます。
PS C:\Users\user\Desktop> ./node_modules/.bin/envinfo
  System:
    OS: Windows 10
    CPU: (4) x64 Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz

PS C:\Users\user\Desktop> npm uninatall envinfo
# envinfoがないので怒られます。
PS C:\Users\user\Desktop> ./node_modules/.bin/envinfo
./node_modules/.bin/envinfo : 用語 './node_modules/.bin/envinfo' は、コマンドレット、関数、スクリプト ファイル、
または操作可能なプログラムの名前として認識されません。名前が正しく記述されていることを確認し、パスが含まれている
場合はそのパスが正しいことを確認してから、再試行してください。

# envinfoがないのに実行できます。(一時的にインストールして実行)
PS C:\Users\user\Desktop> npx envinfo
npx: 1個のパッケージを3.183秒でインストールしました。
  System:
    OS: Windows 10
    CPU: (4) x64 Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz

yarnとnpmは何が違うのか?

まずは、パッケージインストール等のコマンドの指定方法が異なります。

$ npm install express # npmでexpressをインストール!!
$ yarn add express # yarnでexpressをインストール!!
$ npm uninstall express # npmでexpressをアンインストール!!
$ yarn remove express # yarnでexpressをアンインストール!!

また、yarnは並列でパッケージをインストールができるためnpmよりパッケージのインストールが高速らしいです。
さらに、npmでインストールしたパッケージもyarnで実行できます。
そして、パッケージの実行をnpxみたいにyarn xxxで実行できます。
※ただし、npxとは違って実行するパッケージはインストールされている必要があります。

まあ便利なnpmという感じで私は使ってますね。

こちらも、一例を実行してみたので下記ご参照ください。

PS C:\Users\user\Desktop> yarn add envinfo
# npxとはみたいに実行できる
PS C:\Users\user\Desktop> yarn envinfo
  System:
    OS: Windows 10
    CPU: (4) x64 Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz
PS C:\Users\user\Desktop> yarn remove envinfo

# npxとは違って自動でパッケージはインストールしてくれない
PS C:\Users\user\Desktop> yarn envinfo
yarn run v1.15.2
error Command "envinfo" not found. 
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Nuxtプロジェクトを構築してみよう

それでは、Nuxtプロジェクトを構築していきます。
任意の作業ディレクトリで下記を実行します。

PS C:\Users\user\Desktop\project> npx create-nuxt-app

実行するといくつか質問されます。私は下記のように回答しました。

? Project name dev
? Project description dev
? Use a custom server framework none
? Choose features to install Progressive Web App (PWA) Support, Axios
? Use a custom UI framework vuetify
? Use a custom test framework jest
? Choose rendering mode Single Page App
? Author name dev
? Choose a package manager yarn

選択肢について以下で補足したいと思います。

? Use a custom server framework
この選択では、バックエンドのフレームワーク(express等)を選ぶことができます。
今回、バックエンド側はFirebaseに任せてフロントエンド側のみ作る予定なのでnoneにしました。

? Choose features to install Progressive
この選択では、使用したいモジュールを選択すれば一緒にインストールをしてくれます。
将来的に使うかもしれないと思いPWAAxiosを選択してます。
PWAというのは、WEBの技術(HTMLやJavascript)でネイティブアプリのような動作を可能にする仕組みのことです。
Axiosというのは、Promise ベースの HTTP クライアントです。RestAPIの実行とか利用できます。

? Use a custom UI framework
この選択では、UIのフレームワークを選ぶことができます。今回はVuetifyを選択しました。
Vuetifyとは Vue.js 用のUIコンポーネントフレームワークです。
マテリアルデザイン(Googleが推奨するデザイン)の手法に基づいたコンポーネントを提供しています。
手軽にGoogleっぽいデザインな画面を実現できてしまいます。
Vuetifyのコンポーネントのドキュメント:リンク

? Use a custom test framework
この選択では、テストフレームワークを選ぶことができます。今回は簡単でシンプルといわれるjestを選択しました。
ただ、今回の作業では使用していません。テストしてません。

? Choose rendering mode
この選択では、レンダリングモードを選ぶことができます。記事タイトルにも書きましたがSPAを選択してます。
今回なぜSPAにしたのか明確な理由はありません。
ただ、SPAのほうがホスティング先が多くて楽そうと思ったくらいです。
Nuxtの場合だとnuxt generateというコマンドを実行するだけで静的ファイルが吐き出されます。
その静的ファイルをアップするだけでGitHubPageみたいなホスティング先にデプロイできます。
他のレンダリングモードとしてSSRがあります。
SSRでデプロイする場合は Node.js の入ったレンダリングを行うためのサーバが必要になります。

Nuxtを起動してみる

さて、無事にNuxtプロジェクトを生成することができました。
プロジェクトを作成した場所でyarn devコマンドを実行してみましょう。

PS C:\Users\user\Desktop\project> yarn dev

実行する開発用サーバーが起動するのでhttp://localhost:3000/にアクセスして確認することができます。

NuxtにTypeScriptを適用してみる

※今回はNuxt v2.9での適用手順になります。それ以前のバージョンとは手順が異なります。
公式ガイドを参考に適用していきます。

現時点では、NuxtでTypeScriptを使うためには下記の手順を踏む必要があります。

まずは@nuxt/typescript-buildというパッケージをプロジェクトにインストールしましょう。

PS C:\Users\user\Desktop\project> yarn add --dev @nuxt/typescript-build

--devというオプションを付けています。
これは、devDependenciesとしてパッケージを追加する時に付与するオプションです。
開発時のみ該当のパッケージを使用したい時とかはdevDependenciesとしてパッケージを追加するのが通例となっています。
@nuxt/typescript-buildはNuxtでTypeScriptを使用するためのものであり開発時のみで十分です。
逆に開発時以外にも使用するパッケージ(express)などは、dependenciesとしてパッケージを追加します。

続いて、Nuxtで@nuxt/typescript-buildをビルド専用モジュールとして使用したいので、nuxt.config.jsに下記を追記します。

nuxt.config.js
export default {
  buildModules: ['@nuxt/typescript-build']
}

続いて、tsconfig.jsonを新規に作成します。作成する場所はプロジェクト直下で大丈夫です。
tsconfig.jsonの内容は公式ガイドを参考にしましょう。

PS C:\Users\user\Desktop\project> vi tsconfig.json
tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "lib": [
      "esnext",
      "esnext.asynciterable",
      "dom"
    ],
    "esModuleInterop": true,
    "allowJs": true,
    "sourceMap": true,
    "strict": true,
    "noEmit": true,
    "baseUrl": ".",
    "paths": {
      "~/*": [
        "./*"
      ],
      "@/*": [
        "./*"
      ]
    },
    "types": [
      "@types/node",
      "@nuxt/types"
    ]
  },
  "exclude": [
    "node_modules"
  ]
}

続いて、vue-property-decoratorというパッケージを追加しましょう。
vue-property-decoratorはVueアプリをクラススタイルで実装を行う時によく使用されます。
また、TypeScriptではデコレータと呼ばれる既存の関数に対して処理の追加/変更を行う為の機能が用意されています。
vue-property-decoratorを使用することでデコレータを用いたVueアプリの実装が可能になります。
詳しくは、vue-property-decoratorのReadmeを読むことを推奨します。

PS C:\Users\user\Desktop\project> yarn add --dev vue-property-decorator

パッケージの追加が終わったら、先ほど用意したtsconfig.jsoncompilerOptionsに下記を追記してあげましょう。

tsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
  }
}

最後にTypeScriptの書かれたソースコードがしっかりとビルドされるかの動作確認を行います。
先ほど自動生成されたNuxtプロジェクトのpages/index.vueを使って動作確認をしていきます。

pages/index.vue
<script>
import Logo from '~/components/Logo.vue'
import VuetifyLogo from '~/components/VuetifyLogo.vue'

export default {
  components: {
    Logo,
    VuetifyLogo
  }
}
</script>

こちらは自動生成された時のIndexページのScript部分の抜粋です。
これをTypeScriptのクラスベースに書き換えていきましょう。

pages/index.vue
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
import Logo from '~/components/Logo.vue'
import VuetifyLogo from '~/components/VuetifyLogo.vue'

@Component({
  components: {
    Logo,
    VuetifyLogo
  }
})
export default class IndexPage extends Vue {}
</script>

IndexPageクラスという形でクラスベースに置き換えました。
アノテーションを使ってComponent定義を行っています。
作成するクラスにはvue-property-decoratorのVueクラスを忘れずに継承させましょう。

上記の状態でコンパイルが正常に実行されるかyarn devで確認してみましょう。

PS C:\Users\user\Desktop\project> yarn dev

正常にコンパイルされたらhttp://localhost:3000/で画面を確認してみましょう。

以上が、TypeScriptを適用させる手順でした。

ログインページを作成する

さて、一通り環境の構築を終えたところで実装に移っていきます。
login.vueというファイル名のログインページをpagesの中に作りたいと思います。
ログイン認証処理は後述しますが、ひとまず見た目だけ作ってみます。

pages/login.vue
<template>
  <v-form>
    <v-container>
      <v-text-field label="MailAddress" v-model="mail"></v-text-field>
      <v-text-field label="Password" v-model="pass"></v-text-field>
      <v-btn color="primary" @click="login">ログイン</v-btn>
    </v-container>
  </v-form>
</template>

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'

@Component({
  layout: 'default',
  components: {
  }
})
export default class LoginPage extends Vue {
  mail: string = ''
  pass: string = ''

  login() {
    alert('Login !!')
  }
}
</script>

9.png
良い感じにデザインもあたってくれて綺麗な画面が出来上がりました。
さらにこのページはvue-property-decoratorを使用したクラスベースの実装にしています。
v-modelで使用しているDataはクラスメンバとして定義するだけで利用できます。
@clickで使用しているmethodsはクラスメソッドとして定義するだけで利用できます。

続いて、ログイン認証の実装部分に移りますが、ログイン認証にはFirebaseを利用します。
まずは動作確認用としてFirebase上にUserを追加していきましょう。
前述で作成したFirebaseプロジェクトのコンソールにアクセスします。

Firebase上にUserを追加しておく

10.png

上記の画面でログイン方法を設定します。
今回はメールアドレスパスワードの2つでログイン出来るように有効にしました。
メールリンクは無効のままにしています。
メールリンクログインというのは、認証リンクが記載された文面のあるメールをFirebaseがログイン対象のメールアドレス宛に送信します。
受信したメールを確認して認証リンクを踏むことでログイン認証が完了する仕組みになっております。

11.png

ログイン方法の設定が完了したら、上記の画面から動作確認用ユーザを追加しときましょう。

firebaseログインの実装準備

Firebaseログイン実装に移る前に、プロジェクトにクライアント向けSDKをインストールしましょう。公式リファレンス

PS C:\Users\user\Desktop\project> yarn add firebase

パッケージのインストールが完了したら、さっそく使っていきたいと思います。
どのコンポーネントからでも使用できるように、firebaseSDK呼び出し用プラグインでもplugins配下に作っておきましょう。

plugins/firebase.ts
import firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/firestore'

// SDKを使用するためのConfig情報
const firebaseConfig = {
  apiKey: "xxxxxxxxxxx",
  authDomain: "xxxxxxxxxxx",
  databaseURL: "xxxxxxxxxxx",
  projectId: "xxxxxxxxxxx",
  storageBucket: "xxxxxxxxxxx",
  messagingSenderId: "xxxxxxxxxxx",
  appId: "xxxxxxxxxxx",
  measurementId: "xxxxxxxxxxx"
}
// Appの初期化
if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig)
}
// 今回使用するAPI
export const auth = firebase.auth()
export const firestore = firebase.firestore()

これで、使用したい場所でimport { auth } from 'plugins/firebase'みたいに使えるようになりました。

firebaseConfigってどこにあるの?
SDKを使用する場合、事前にFirebaseプロジェクト内にアプリを追加しておく必要があります。
アプリの追加手順を以下にまとめます。

まずは、Firebaseプロジェクトのコンソールにいきましょう。
12.png
上記の画面で「</>」のボタンを押します。
13.png
次に、上記の画面でアプリのニックネームを決めてアプリの登録ボタンを押します。
14.png
今回はNPMを使うので、この画面はスルーで良いです。
15.png
この画面は、firebase-toolsというパッケージをインストールする場合の手順が記載されています。
FirebaseにはHostingのサービスがあります。
firebase-toolsはローカルからFirebaseへデプロイする時にポチポチする時に使ったりします。
今回はHostingをする予定がないので、スルーで良いです。
16.png
今回はHostingをする予定がないので、スルーで良いです。
17.png
アプリの追加が終わったら、上記画面からFirebaseConfig情報をコピーすることが出来るようになりましたので、
先ほどのplugins/firebase.tsに貼り付けてやりましょう。

firebaseログインの実装

では、Firebaseログインを実装します。
先ほど作成したpages/login.vueとレイアウトは変わらないで処理の部分だけ以下に載せます。

pages/login.vue
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
import { auth } from '../plugins/firebase'

@Component({
  layout: 'default',
  components: {
  }
})
export default class LoginPage extends Vue {
  mail: string = ''
  pass: string = ''

  login() {
    auth.signInWithEmailAndPassword(this.mail, this.pass)
      .then(user => this.$router.push('/'))
      .catch(e => alert(e.message))
  }
}
</script>

たった3行でログイン処理を実装できてしまいました。
ログインに成功したらTopページへ遷移、失敗したらアラートでエラー内容を表示という実装になります。

次に、Topページにログアウト処理も作ってしまいます。

pages/index.vue
<template>
  <v-container>
    <div v-if="isLogin"><v-btn @click="logout">ログアウト</v-btn></div>
  </v-container>
</template>

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
import { auth } from '../plugins/firebase'

@Component({
  layout: 'default',
  components: {
  }
})
export default class IndexPage extends Vue {
  isLogin:boolean = false
  async mounted() {
    await auth.onAuthStateChanged((user) => this.isLogin = user ? true : false)
  }
  async logout() {
    await auth.signOut()
    this.$router.push('/login')
  }
}
</script>

上記の実装では、ログイン中かどうかを分かりやすくするために、ログイン認証済みの場合はログアウトボタンが出現するような仕組みにしています。
ログインしていれば、ログアウトボタンが表示されます。
ちなみに、onAuthStateChanged関数で、認証状態の変化を監視します。
認証されていれば、ログイン中のuser情報を返します。

ただ、このままではログインしなくてもトップページへ遷移できてしまいますね。。。

さて、ログインしていない場合はTopページ(というか全てのページ)にアクセスできない仕組みを施します。
middleware配下にauth.ts(ファイル名は任意)を作成しましょう。

middleware\auth.ts
import { Middleware } from '@nuxt/types'
import { auth } from '../plugins/firebase'

const middleware:Middleware = ({ route, store, redirect }) => {
  auth.onAuthStateChanged((user) => {
    if (! user && route.name !== 'login') redirect('/login')
  })
}
export default middleware

先ほどのpages/index.vuemountedで実装していた内容に似ていますね。
ログインされていないかつアクセスされたURLが/loginでない場合は強制的に/loginへリダイレクトさせてます。
※先ほどのpages/index.vueに記載したmountedの内容はもう不要なので適宜消してしまってくださいね。

ただ、このままではミドルウェアが反映されません。
ミドルウェアの作成が終わったらnuxt.config,jsに下記を追記してやります。

nuxt.config.js
  router: {
    middleware: ['auth']
  },

これにより全てのページに対してmiddlware/auth.tsが適用されます。

以上、Firebaseログインの実装になります。

長くなってしまいましたが、Nuxt+Firebaseでのログイン処理実装でした。
ぜひ、参考にしていただければ幸いです!!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away