令和最新版 firebase + nuxt3のwebアプリ開発手順③
Firebase + Nuxt3開発
- Nuxt3アプリ作成〜firebaseデプロイ
- TailwindCSSの導入
- ログイン機能の実装
- firestoreを使ったデータの読み取り、書き込み、更新
全体像
- firebase関係はcomposableにuseFirebaseを置いておき、ここからauthを使えるようにしています。
- ログインのチェックおよび非ログインの場合にログイン画面に遷移させる動作はmiddlewareに記述
Middleware
nuxtにおけるmiddlewareの役割は、主にページ遷移時において、ページを表示させる直前の動作を規定するものです。
フロントサイドのsetupとの違いは、setupはページ自体は表示させる前提でDOM作成のためのデータ処理を行うのに対して、middlewareはページ遷移自体を発生させるかやページ自体を表示させるかどうかの判定をしているものです。
利用用途はログイン処理くらいしか思い浮かびませんが、、、
middleware/auth.ts
export default defineNuxtRouteMiddleware(async () => {
if (!process.server) {
const {auth} = useFirebase()
if (!auth.currentUser) {
return await navigateTo('/', { replace: false })
}
}
})
ログインしていればauth.currentUserにはuidやdisplayNameが格納されています。
ログインしてなければauth.currentUserはundefinedです。
よって、このコードでは、ログインしていなければnavigateToで'/'に遷移するという意味です。
Pages
pages/mypage.vue
<script setup lang="ts">
definePageMeta({
middleware: ['auth'],
})
以下略
ログインしていなければ表示させたくないページには、先ほど作成したmiddlewareの処理を実行させるための記述をします。
注意
本来、ログインチェックは全てのページで行いたいので、middleware authはグローバル設定したいところですが、ミドルウェアをグローバル設定するとnavigateToはVue Routerで無限ループを引き起こしてしまうバグがあるようです。
ですので、今のところはグローバル設定は行わず、各ページにmiddleware authを記述してログインチェックとページ遷移を行います。
app設定
ミドルウェアはpagesに対しては有効ですが、レイアウトページ(nuxt3ではapp.vue)に対しては無効です。
また、以下のようにログイン有無によって表示を変える設定をしてると、ログインした後にauth.currentUserの変更は読み取れないため、ログインした後も「ログインする」の表示が残ったままになってしまいます。
app.vue
<script setup lang="ts">
const {auth} = useFirebase()
const {currentUser} = auth
</script>
<template>
<div class="w-screen h-screen flex flex-col">
<nav class="w-full flex justify-between h-12 px-4 py-2" >
<NuxtLink to="/" class="flex items-end">
<img src="/Logo.png" width="130" class="mr-3">
</NuxtLink>
<ul class="flex self-center space-x-3">
<!-- ログインしていない時だけ表示 -->
<li v-if="!currentUser">
<NuxtLink to='/login' class="mx-4">ログイン</NuxtLink>
</li>
<!-- ログインしている時だけ表示 -->
<li v-if="currentUser">
<NuxtLink to='/mypage' class="mx-4">マイページ</NuxtLink>
</li>
</ul>
</nav>
</div>
<template>
この問題に対処するには、onAuthStateChangedを用いてレイアウトページでログイン状態の変化を感知してやります。
app.vue
<script setup lang="ts">
import {onAuthStateChanged} from 'firebase/auth'
const {auth} = useFirebase()
const isLogin = ref(false)
onAuthStateChanged(auth,(user)=>{
isLogin.value = user? true:false
})
</script>
<template>
<div class="w-screen h-screen flex flex-col">
<nav class="w-full flex justify-between h-12 px-4 py-2" >
<NuxtLink to="/" class="flex items-end">
<img src="/Logo.png" width="130" class="mr-3">
</NuxtLink>
<ul class="flex self-center space-x-3">
<!-- ログインしていない時だけ表示 -->
<li v-if="!isLogin">
<NuxtLink to='/login' class="mx-4">ログイン</NuxtLink>
</li>
<!-- ログインしている時だけ表示 -->
<li v-if="isLogin">
<NuxtLink to='/mypage' class="mx-4">マイページ</NuxtLink>
</li>
</ul>
</nav>
</div>
<template>
Discussion