令和最新版 firebase + nuxt3のwebアプリ開発手順④
全体像
- Nuxt3アプリ作成〜firebaseデプロイ
- TailwindCSSの導入
- ログイン機能の実装
- firestoreを使ったデータの読み取り、書き込み、更新
設計概要
firebaseの関数はサーバー側で実行します。
- servers/apiにfirebaseの初期化処理や各コンポーネントで利用する関数を配置します。
- 各コンポーネントからはuseFetchでデータを取得できます。
※以下リンクで紹介されている方法とほとんど同じです
※firebaseの処理をフロント側で実行する方法もあります。
しかし、フロント側で実行する方法では、ページ読み込み時にdbオブジェクトを利用する方法を確立できなかったため、今の私はサーバー側で実行する方法をとっています。
フロント側で実行する方法ではSDKでconfig({apiKey:~~~,authDomain:~~~と書いてあるやつ)でinitializeAppを実行できましたが、サーバー側で実行する方法では秘密鍵でinitializeAppを実行します。SDKで実行できないので注意。
どういったアプリか
- ユーザー認証はfirebase authのメール認証を用いています。
- dbはfirestoreを用い、データは以下のような鬼滅の刃のキャラクターです。
秘密鍵の取得
- firebaseコンソールで秘密鍵(jsonファイル)を取得します。
- アプリのルートディレクトリに秘密鍵のjsonファイルを保存
- gitignoreに記載することを忘れずに
server/api/firebase.ts
import { getFirestore } from 'firebase-admin/firestore'
import { initializeApp, getApps, cert } from 'firebase-admin/app'
const apps = getApps()
if (!apps.length) {
initializeApp({
credential: cert('./himitsukagi.json') // ../../himitsukagiではなく、./です
})
}
export default async (request, response) => {
const db = getFirestore()
const usersSnap = await db.collection('users').get()
const usersData = usersSnap.docs.map(doc => {
return {
id: doc.id,
...doc.data()
}
})
return usersData
}
これでコンポーネントからは以下のようにしてデータを取得できます
const {data:usersData} = await useFetch('/api/firebase')
app.vue
クリックで表示
<script setup lang="ts">
type page = {
title:string,
icon:string,
to:string
}
const pages = <page[]> [
{
title:'firestoreテスト',
icon:'',
to:'/dbtest'
},{
title:'authテスト',
icon:'',
to:'/authtest'
}
]
</script>
<template>
<div class="w-screen h-screen flex flex-col">
<nav class=" bg-cyan-200 w-full flex justify-between h-12 px-4 py-2" >
<div class="text-xl font-bold"> ナビゲーション</div>
<ul class="flex self-end">
<li v-for="menu of ['Home','About','Services','Pricing','Contact']">
<div class="mx-4">{{menu}}</div>
</li>
</ul>
</nav>
<div class="flex h-full">
<aside class=" w-48 bg-gray-200">
<ul>
サイドメニュー
<li v-for="page in pages">
<button class="my-3 px-3 text-center">
<NuxtLink :to="page.to">{{page.title}}</NuxtLink>
</button>
</li>
</ul>
</aside>
<main class="w-full">
<div class="bg-lime-100 h-full">
<NuxtPage></NuxtPage>
</div>
</main>
</div>
</div>
</template>
pages/dbtest.vue
クリックで表示
<script setup lang="ts">
type User = {
id:String,
name:String
}
type Users = Array<User>
const {data:users} = await useFetch('/api/firebase')
</script>
<template>
<h2 class=" text-2xl">firestoreテスト</h2>
{{users}}
</template>
それにしてもuseFetchを使うと、めちゃくちゃシンプルに書けますね
ビルドとエミュレーターテスト
yarn run devで動くことが確認できたら、エミュレーターでテストしましょう
$ NITRO_PRESET=firebase yarn build
$ firebase emulators:start
おそらくdbtestのページを開こうとすると失敗する(ページ自体は開くがデータを取得できない)はずです。
エラーメッセージを見ると、秘密鍵のファイルがありませんと出ています。
エラー元になっている次のファイルを見てみましょう。
.output/server/chunks/firebase.mjs
さっきまで書いていたserver/api/firebase.tsと同じ内容です。
yarn run devで動かしていたときはserver/api/firebase.tsから秘密鍵のjsonファイルを参照していましたが、firebase emulatorsで動かしているときは.output/server/chunks/firebase.mjsから秘密鍵のjsonファイルを探そうとしているため、見つからないはずです。
対処法としては、.output/serverディレクトリに秘密鍵のjsonファイルを入れてやることで、エミュレーターテストやデプロイで問題なく動くようになります。
しかし、それだとビルドのたびに秘密鍵のjsonファイルが消えるので、毎回秘密鍵のjsonを貼り付ける必要があります。
対処法募集
そこで、functionsの環境変数に秘密鍵のjsonの内容を記載してやりました。
$ firebase functions:config:set credential="・・・"
server/api/firebase.json
+import * as functions from 'firebase-functions'
if (!apps.length) {
+ const config = functions.config()
initializeApp({
+ credential: config.credential? config.credential:cert('./engineer-house-firebase-adminsdk-iju2g-98ad0c900c.json')
})
}
しかし現状はfunctions.config().credentialを認識してくれません。
解決法募集しています。
作成、更新、削除は追って作成します
Discussion