🐷

【2024年3月更新】 firebase + nuxt3のwebアプリ開発手順③

2021/12/05に公開
更新履歴

2024年3月 内容更新

記事①と②に合わせて書き方を更新しました

2023年10月 ユーザープロフィールはどこに書くかを作成

2023年7月 plugins/firebase.tsで、provideを返す書き方に変更。

2023年3月 ログイン時と非ログイン時のルーティングを作成

2023年2月 導入手順を作成

全体像

  1. Nuxt3アプリ作成〜firebaseデプロイ
  2. 各種スタイル用フレームワーク、ライブラリの導入
  3. ログイン機能の実装
  4. firestoreを使ったデータの読み取り、書き込み、更新

設計思想

ここからfirebase authやfirebase storeなどfirebaseの機能をどんどん導入していきます。
作り始める前に、最終的にどのような形になっているのか目標を理解しましょう。

plugins/firebase.ts

クリックで展開
import { initializeApp } from "firebase/app";
// import { getAnalytics } from "firebase/analytics";

import { getAuth } from "firebase/auth";

export default defineNuxtPlugin(() => {

    const firebaseConfig = {
      apiKey: "****",
      authDomain: "***",
      projectId: "***",
      storageBucket: "***",
      messagingSenderId: "***",
      appId: "***",
      measurementId: "***"
    };

    initializeApp(firebaseConfig);

    return {
        provide: {
            auth:getAuth(),
        }
    }
})
  • firebaseではアプリ立ち上げ時に一度だけ、firebase認証(初期化)をする必要があります。
    initializeApp(firebaseConfig);

  • Nuxt3ではpluginsフォルダに記載したプログラムが、立ち上げ時に一度だけ実行されるので、ここにfirebase認証(初期化処理)を書いてやりましょう。

  • 私流のやり方ですが、provideをreturnしています。これはNuxt3のやり方で、pluginsでprovideで返したプロパティはページやコンポーネントで$で使うことができるからです。

const {$auth, $db} = useNuxtApp()

middleware/auth.global.ts

クリックで展開
import {getAuth, onAuthStateChanged} from '@firebase/auth'

export default defineNuxtRouteMiddleware( async(to,from) => {
    if (!process.server) {

      const checkAuthState = new Promise((resolve, reject) => {
          onAuthStateChanged(getAuth(), async user => {
            if (user) {
              resolve(user)
            } else {
              reject()
            }
          })
      })
      
      try {
          const user = await checkAuthState
          console.log('ログインしています')
      } catch (err) {
          console.log('ログインしていません!')
          // 例 ログインしていなくてもトップページとauthページは見れるが、それ以外のページではauthページにリダイレクトさせる
          if(to.path==="/" || to.path.startsWith('/auth')){
            return
          }else{
            return await navigateTo('/auth') 
          }
      }
    }
  })
  • ログイン有無によるルーティング(例えばログインしていない状態でプロフィール編集画面を開こうとすると、ログインページに飛ばす)を設定するにはmiddlewareを使います。

導入手順

Authenticationを有効化

firebaseコンソールで有効化してください。
(普通はパスワード認証とGoogle認証を有効化しとけば十分でしょう。イーロンの暴挙を見るにX(twitter)はやらないほうが良いかも)

firebase toolsの導入

plugins/firebase.tsでインポートするfirebase/appfirebase/authを利用するために、firebase toolを導入します

$ npm install firebase

plugins/firebase.tsの作成

  • apiKeyなどをベタ書きするのは良くないですが、ひとまず動作確認はこれでやります
plugins/firebase.ts
import { initializeApp } from "firebase/app";
// import { getAnalytics } from "firebase/analytics"; 必要に応じて有効化

export default defineNuxtPlugin( () => {
    const firebaseConfig = {
        apiKey: "***************",
        authDomain: "**************",
        databaseURL: "**************",
        projectId: "**************",
        storageBucket: "**************",
        messagingSenderId: "**************",
        appId: "**************",
        measurementId: "**************"
    };
    
    initializeApp(firebaseConfig)
    
    return {
        provide: {
            auth:getAuth(),
        }
    }
})

middlewareにログイン時and非ログイン時の処理を実装

基本は冒頭の書き方で良いでしょう。

例えばユーザー情報でauthに収められない情報(課金ユーザーであるか、所属している会社など)がある場合は、それらの情報をfirebase cloudstoreのusersに入れていることがあると思います。
そういった情報はuseStateに'currentUser'を作って格納しておくと何かと便利です。

以下のように書くことで、ログイン中ユーザーの情報をstoreから引っ張ってくる動作を「ログイン時の一度だけ」にすることができます。

      try {
          const user = await checkAuthState
          console.log('ログインしています')
          const {$db} = useNuxtApp()
          const userRef = doc($db,'users',user.uid)
          const userSnap = await getDoc(userRef)
          if(userSnap.exists()){
            useState('currentUser').value = userSnap.data()
          }
          
      } catch (err) {
          console.log('ログインしていません!')
      }

RuntimeConfigを使ってキーを隠す

.envファイルに以下のように書きます。

  • NUXT_PUBLICを冒頭につける
  • 全て大文字
NUXT_PUBLIC_FB_API_KEY=****
NUXT_PUBLIC_FB_AUTH_DOMAIN=****
NUXT_PUBLIC_FB_PROJECT_ID =****
NUXT_PUBLIC_FB_STORAGE_BUCKET=****
NUXT_PUBLIC_FB_MESSAGING_SENDER_ID=****
NUXT_PUBLIC_FB_APP_ID=****
NUXT_PUBLIC_FB_MEASUREMENT_ID=****

次にnuxt.config.tsにruntimeConfigとして環境変数を設定します。
上記でNUXT_PUBLICとつけたので、runtimeconfig.publicで環境変数を使用できます

export default defineNuxtConfig({
  ・・・
  runtimeConfig:{
    public:{
      googleMapsApiKey:process.env.NUXT_PUBLIC_GOOGLE_MAPS_API_KEY,
      resasApiKey:process.env.NUXT_PUBLIC_RESAS_API_KEY,
      apiKey: process.env.NUXT_PUBLIC_FB_API_KEY,
      authDomain: process.env.NUXT_PUBLIC_FB_AUTH_DOMAIN,
      projectId: process.env.NUXT_PUBLIC_FB_PROJECT_ID,
      storageBucket: process.env.NUXT_PUBLIC_FB_STORAGE_BUCKET,
      messagingSenderId: process.env.NUXT_PUBLIC_FB_MESSAGING_SENDER_ID,
      appId: process.env.NUXT_PUBLIC_FB_APP_ID,
      measurementId: process.env.NUXT_PUBLIC_FB_MEASUREMENT_ID
    }
  }
}

最後にplugins/firebase.tsで環境変数の呼び出しです。
useRuntimeConfig()で環境変数呼び出しします。

・・・
export default defineNuxtPlugin(() => {
    const config = useRuntimeConfig()

    const firebaseConfig = {
        apiKey: config.public.apiKey,
        authDomain: config.public.authDomain,
        projectId: config.public.projectId,
        storageBucket: config.public.storageBucket,
        messagingSenderId: config.public.messagingSenderId,
        appId: config.public.appId,
        measurementId: config.public.measurementId
    };
    // 以下略
})

Discussion