過去兩天,我們成功接入 Gemini 的文字與多模態視覺能力。現在,《喵語日誌》中的貓咪已經能根據使用者輸入的文字與上傳的照片,提供即時且動態的陪伴回覆。
不過,目前這些資料仍然只存在於前端記憶體中。只要使用者重新整理網頁,剛剛的對話、照片與情緒紀錄就會全部消失。
如果要讓《喵語日誌》成為真正實用的情緒日記工具,就必須將資料持久化保存。
因此,今天正式導入 Google 提供的 Serverless 解決方案——Firebase,完成專案建立、SDK 整合與匿名登入功能,為後續的雲端資料儲存做好準備。
在開發輕量型 Web 應用或產品原型時,如果自行架設 Node.js、Express 與 PostgreSQL,除了要處理程式邏輯之外,也需要花費時間維護伺服器、資料庫、驗證機制與部署環境。
Firebase 則提供了一套整合完成的雲端服務,包含:
使用者驗證
Firestore 雲端資料庫
Cloud Storage 檔案儲存
Hosting 網站部署
其他後端相關服務
透過這些服務,我可以將更多時間放在《喵語日誌》的產品功能與使用者體驗上,而不需要一開始就處理大量基礎設施問題。
更重要的是,Firebase Auth 提供了「匿名登入」功能,非常適合目前的使用情境。
《喵語日誌》是一款以陪伴與情緒記錄為核心的應用程式。如果使用者第一次開啟 App,就必須先註冊帳號、設定密碼,或綁定社群帳號,可能會增加不必要的操作負擔。
透過匿名登入,使用者不需要填寫任何資料,系統就能在第一次造訪時,自動建立一組專屬的 Firebase UID。
這組 UID 可以作為使用者在雲端資料庫中的識別依據,讓每位使用者擁有獨立的資料空間。
未來如果使用者想要升級成 Google 帳號或其他登入方式,也可以再進行帳號綁定,延續原本的資料。如此一來,便能在「低進入門檻」與「後續擴充性」之間取得平衡。
首先,我在 Firebase Console 建立新的專案,接著在 Authentication 設定中啟用匿名登入方式。
接著安裝 Firebase 官方套件:
npm install firebase
為了避免將設定直接寫死在原始碼中,我將 Firebase 設定抽離到 .env 環境變數檔案,再透過 Vite 的 import.meta.env 讀取。
# .env
VITE_FIREBASE_API_KEY=我們的_apiKey
VITE_FIREBASE_AUTH_DOMAIN=我們的_authDomain
VITE_FIREBASE_PROJECT_ID=我們的_projectId
VITE_FIREBASE_STORAGE_BUCKET=我們的_storageBucket
VITE_FIREBASE_MESSAGING_SENDER_ID=我們的_messagingSenderId
VITE_FIREBASE_APP_ID=我們的_appId
這樣可以讓設定與程式碼分離,也能降低將環境設定直接寫入版本控制系統的風險。
需要注意的是,.env 檔案仍然應該加入 .gitignore,避免不必要的設定資訊被提交到公開儲存庫。
完成環境變數設定後,我在 src/services/firebase.ts 中初始化 Firebase App,並建立 Authentication 與 Firestore 的服務實例。
// src/services/firebase.ts
import { initializeApp } from "firebase/app";
import {
getAuth,
onAuthStateChanged,
signInAnonymously,
type User,
} from "firebase/auth";
import { getFirestore } from "firebase/firestore";
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID,
};
const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const db = getFirestore(app);
接著,我封裝 initAnonymousAuth 函式,統一處理登入狀態監聽與匿名登入流程。
export function initAnonymousAuth(
onUserLoaded: (user: User) => void
) {
return onAuthStateChanged(auth, async (user) => {
if (user) {
console.log("現有使用者 UID:", user.uid);
onUserLoaded(user);
return;
}
try {
const userCredential = await signInAnonymously(auth);
console.log(
"新匿名使用者已登入,UID:",
userCredential.user.uid
);
onUserLoaded(userCredential.user);
} catch (error) {
console.error("匿名登入失敗:", error);
}
});
}
這段流程會先透過 onAuthStateChanged 檢查目前的登入狀態。
如果瀏覽器中已經存在先前建立的匿名使用者,系統就會直接取得現有的 User。如果沒有找到使用者,才會呼叫 signInAnonymously 建立新的匿名身分。
如此一來,重新整理頁面時不需要每次都重複發起登入請求,也能保留使用者的登入狀態。
完成服務封裝後,我在 src/App.tsx 中使用 useEffect 掛載登入狀態監聽。
useEffect(() => {
const unsubscribe = initAnonymousAuth((currentUser) => {
setUser(currentUser);
console.log(
"🎯 App 成功連線 Firebase,使用者 UID 為:",
currentUser.uid
);
});
return () => unsubscribe();
}, []);
onAuthStateChanged 會回傳一個取消監聽的函式,因此在元件卸載時呼叫 unsubscribe(),可以避免不必要的監聽持續存在。
取得使用者資料後,再將 currentUser 儲存到 React State 中,後續便能使用這組 UID 進行 Firestore 資料讀寫。
完成程式整合後,我啟動本地開發伺服器,並開啟瀏覽器開發者工具進行測試。
▲ 前端成功觸發匿名登入並取得 UID:gf8k4vppmmdu3GAGIma1Sdqk4wk1
在 Firebase Console 中,也能看到對應的匿名使用者紀錄。
▲ Firebase Console 後台同步建立匿名使用者資料
接著進行重新整理測試,onAuthStateChanged 能夠正確捕捉到原本的使用者身分,不需要重新建立新的匿名帳號。
這代表目前的匿名登入流程已經成功運作,使用者也具備了後續儲存個人資料所需的專屬 UID。
這次整合 Firebase Auth 的過程比預期中直覺許多。
匿名登入不只簡化了使用者的首次操作流程,也解決了雲端資料需要身分識別的問題。使用者不需要先註冊帳號,系統就能在背景建立一組專屬的 UID,讓資料可以被正確區分與保存。
從產品角度來看,這是一個很重要的基礎功能。對使用者而言,登入流程幾乎是無感的;對開發者而言,則已經具備了建立個人化資料空間的條件。
當然,匿名登入並不代表資料可以完全不受管理。後續仍需要搭配適當的 Firestore Security Rules,確保使用者只能讀取與修改自己的資料。
今天我們順利完成了 Firebase 基礎建設與匿名登入功能,為每位使用者建立了專屬的隱形身分證,讓《喵語日誌》正式具備連接雲端服務的能力。
有了獨立的身分識別後,明天我們將進入資料持久化的核心環節:使用 Firestore 將對話與情緒標籤寫入雲端資料庫。我們將設計 NoSQL 文件結構,把 Gemini 分析的情緒分數、生活場景標籤、對話內容與時間戳記完整保存,讓每一次與貓咪的互動都能真正留存下來,成為專屬於使用者的溫暖紀錄。
明天見,喵~