firebase-app-platform
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFirebase App Platform
Firebase应用平台
Ship mobile and web backends with Firebase managed services.
借助Firebase托管服务交付移动和网页后端。
When to Use This Skill
何时使用此技能
Use this skill when:
- Building mobile or web apps with real-time data sync
- Need authentication with minimal backend code
- Prototyping quickly with managed infrastructure
- Building serverless APIs with Cloud Functions
- Hosting static sites or SPAs with CDN
在以下场景使用此技能:
- 构建具备实时数据同步功能的移动或网页应用
- 需要用最少的后端代码实现认证功能
- 借助托管基础设施快速原型开发
- 使用Cloud Functions构建无服务器API
- 通过CDN托管静态站点或单页应用(SPA)
Prerequisites
前提条件
- Node.js 18+
- Firebase CLI ()
npm install -g firebase-tools - Google Cloud account (Firebase is part of GCP)
- A Firebase project (create at console.firebase.google.com)
- Node.js 18+
- Firebase CLI ()
npm install -g firebase-tools - Google Cloud账号(Firebase是GCP的一部分)
- 一个Firebase项目(在console.firebase.google.com创建)
Quick Start
快速开始
bash
undefinedbash
undefinedInstall and authenticate
安装并认证
npm install -g firebase-tools
firebase login
npm install -g firebase-tools
firebase login
Initialize in your project directory
在项目目录中初始化
firebase init
firebase init
Select: Firestore, Functions, Hosting, Emulators
选择:Firestore、Functions、Hosting、Emulators
Start local emulators
启动本地模拟器
firebase emulators:start
firebase emulators:start
Deploy everything
部署所有服务
firebase deploy
firebase deploy
Deploy specific services
部署特定服务
firebase deploy --only functions
firebase deploy --only hosting
firebase deploy --only firestore:rules
undefinedfirebase deploy --only functions
firebase deploy --only hosting
firebase deploy --only firestore:rules
undefinedFirestore Database
Firestore数据库
Security Rules
安全规则
javascript
// firestore.rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Users can only read/write their own data
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
// Messages: authenticated users can read, only owner can write
match /channels/{channelId}/messages/{messageId} {
allow read: if request.auth != null;
allow create: if request.auth != null
&& request.resource.data.userId == request.auth.uid
&& request.resource.data.body is string
&& request.resource.data.body.size() <= 5000;
allow update, delete: if request.auth != null
&& resource.data.userId == request.auth.uid;
}
// Admin-only collection
match /admin/{document=**} {
allow read, write: if request.auth != null
&& get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
}
// Default: deny everything
match /{document=**} {
allow read, write: if false;
}
}
}javascript
// firestore.rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// 用户仅能读写自己的数据
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
// 消息:已认证用户可读取,仅所有者可写入
match /channels/{channelId}/messages/{messageId} {
allow read: if request.auth != null;
allow create: if request.auth != null
&& request.resource.data.userId == request.auth.uid
&& request.resource.data.body is string
&& request.resource.data.body.size() <= 5000;
allow update, delete: if request.auth != null
&& resource.data.userId == request.auth.uid;
}
// 仅管理员可访问的集合
match /admin/{document=**} {
allow read, write: if request.auth != null
&& get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
}
// 默认:拒绝所有操作
match /{document=**} {
allow read, write: if false;
}
}
}Data Operations
数据操作
typescript
// lib/firestore.ts
import { getFirestore, collection, doc, setDoc, getDoc,
query, where, orderBy, limit, onSnapshot,
serverTimestamp, increment } from "firebase/firestore";
const db = getFirestore();
// Create document with auto-ID
async function createMessage(channelId: string, body: string, userId: string) {
const ref = doc(collection(db, "channels", channelId, "messages"));
await setDoc(ref, {
body,
userId,
createdAt: serverTimestamp(),
});
return ref.id;
}
// Real-time listener
function subscribeToMessages(channelId: string, callback: (msgs: any[]) => void) {
const q = query(
collection(db, "channels", channelId, "messages"),
orderBy("createdAt", "desc"),
limit(50)
);
return onSnapshot(q, (snapshot) => {
const messages = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
callback(messages);
});
}
// Atomic counter
async function incrementViews(postId: string) {
await setDoc(doc(db, "posts", postId), {
views: increment(1),
}, { merge: true });
}typescript
// lib/firestore.ts
import { getFirestore, collection, doc, setDoc, getDoc,
query, where, orderBy, limit, onSnapshot,
serverTimestamp, increment } from "firebase/firestore";
const db = getFirestore();
// 创建带自动ID的文档
async function createMessage(channelId: string, body: string, userId: string) {
const ref = doc(collection(db, "channels", channelId, "messages"));
await setDoc(ref, {
body,
userId,
createdAt: serverTimestamp(),
});
return ref.id;
}
// 实时监听器
function subscribeToMessages(channelId: string, callback: (msgs: any[]) => void) {
const q = query(
collection(db, "channels", channelId, "messages"),
orderBy("createdAt", "desc"),
limit(50)
);
return onSnapshot(q, (snapshot) => {
const messages = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
callback(messages);
});
}
// 原子计数器
async function incrementViews(postId: string) {
await setDoc(doc(db, "posts", postId), {
views: increment(1),
}, { merge: true });
}Indexes
索引
json
// firestore.indexes.json
{
"indexes": [
{
"collectionGroup": "messages",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "channelId", "order": "ASCENDING" },
{ "fieldPath": "createdAt", "order": "DESCENDING" }
]
}
]
}json
// firestore.indexes.json
{
"indexes": [
{
"collectionGroup": "messages",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "channelId", "order": "ASCENDING" },
{ "fieldPath": "createdAt", "order": "DESCENDING" }
]
}
]
}Authentication
认证
typescript
// lib/auth.ts
import { getAuth, signInWithPopup, GoogleAuthProvider,
createUserWithEmailAndPassword, signInWithEmailAndPassword,
signOut, onAuthStateChanged } from "firebase/auth";
const auth = getAuth();
// Google sign-in
async function signInWithGoogle() {
const provider = new GoogleAuthProvider();
const result = await signInWithPopup(auth, provider);
return result.user;
}
// Email/password registration
async function register(email: string, password: string) {
const result = await createUserWithEmailAndPassword(auth, email, password);
return result.user;
}
// Auth state listener
onAuthStateChanged(auth, (user) => {
if (user) {
console.log("Signed in:", user.uid, user.email);
} else {
console.log("Signed out");
}
});typescript
// lib/auth.ts
import { getAuth, signInWithPopup, GoogleAuthProvider,
createUserWithEmailAndPassword, signInWithEmailAndPassword,
signOut, onAuthStateChanged } from "firebase/auth";
const auth = getAuth();
// Google登录
async function signInWithGoogle() {
const provider = new GoogleAuthProvider();
const result = await signInWithPopup(auth, provider);
return result.user;
}
// 邮箱/密码注册
async function register(email: string, password: string) {
const result = await createUserWithEmailAndPassword(auth, email, password);
return result.user;
}
// 认证状态监听器
onAuthStateChanged(auth, (user) => {
if (user) {
console.log("已登录:", user.uid, user.email);
} else {
console.log("已登出");
}
});Cloud Functions
Cloud Functions
typescript
// functions/src/index.ts
import { onRequest } from "firebase-functions/v2/https";
import { onDocumentCreated } from "firebase-functions/v2/firestore";
import { getFirestore } from "firebase-admin/firestore";
import { initializeApp } from "firebase-admin/app";
initializeApp();
const db = getFirestore();
// HTTP function (API endpoint)
export const api = onRequest({ cors: true, region: "us-central1" }, async (req, res) => {
if (req.method !== "GET") {
res.status(405).send("Method not allowed");
return;
}
const snapshot = await db.collection("posts").orderBy("createdAt", "desc").limit(10).get();
const posts = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
res.json({ posts });
});
// Firestore trigger — runs when a new message is created
export const onMessageCreated = onDocumentCreated(
"channels/{channelId}/messages/{messageId}",
async (event) => {
const data = event.data?.data();
if (!data) return;
// Update channel's last message timestamp
await db.doc(`channels/${event.params.channelId}`).update({
lastMessageAt: data.createdAt,
messageCount: FieldValue.increment(1),
});
// Send notification (example)
console.log(`New message in ${event.params.channelId}: ${data.body.substring(0, 50)}`);
}
);typescript
// functions/src/index.ts
import { onRequest } from "firebase-functions/v2/https";
import { onDocumentCreated } from "firebase-functions/v2/firestore";
import { getFirestore } from "firebase-admin/firestore";
import { initializeApp } from "firebase-admin/app";
initializeApp();
const db = getFirestore();
// HTTP函数(API端点)
export const api = onRequest({ cors: true, region: "us-central1" }, async (req, res) => {
if (req.method !== "GET") {
res.status(405).send("方法不允许");
return;
}
const snapshot = await db.collection("posts").orderBy("createdAt", "desc").limit(10).get();
const posts = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
res.json({ posts });
});
// Firestore触发器 — 新消息创建时运行
export const onMessageCreated = onDocumentCreated(
"channels/{channelId}/messages/{messageId}",
async (event) => {
const data = event.data?.data();
if (!data) return;
// 更新频道的最后消息时间戳
await db.doc(`channels/${event.params.channelId}`).update({
lastMessageAt: data.createdAt,
messageCount: FieldValue.increment(1),
});
// 发送通知(示例)
console.log(`频道${event.params.channelId}收到新消息: ${data.body.substring(0, 50)}`);
}
);Hosting
托管
json
// firebase.json
{
"hosting": {
"public": "dist",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{ "source": "/api/**", "function": "api" },
{ "source": "**", "destination": "/index.html" }
],
"headers": [
{
"source": "**/*.@(js|css|svg|png|jpg|webp|woff2)",
"headers": [{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }]
},
{
"source": "**",
"headers": [
{ "key": "X-Frame-Options", "value": "DENY" },
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "Strict-Transport-Security", "value": "max-age=63072000" }
]
}
]
}
}json
// firebase.json
{
"hosting": {
"public": "dist",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{ "source": "/api/**", "function": "api" },
{ "source": "**", "destination": "/index.html" }
],
"headers": [
{
"source": "**/*.@(js|css|svg|png|jpg|webp|woff2)",
"headers": [{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }]
},
{
"source": "**",
"headers": [
{ "key": "X-Frame-Options", "value": "DENY" },
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "Strict-Transport-Security", "value": "max-age=63072000" }
]
}
]
}
}Local Emulators
本地模拟器
bash
undefinedbash
undefinedStart all emulators
启动所有模拟器
firebase emulators:start
firebase emulators:start
Start specific emulators
启动特定模拟器
firebase emulators:start --only auth,firestore,functions
firebase emulators:start --only auth,firestore,functions
Export emulator data for persistence
导出模拟器数据以持久化
firebase emulators:export ./emulator-data
firebase emulators:start --import=./emulator-data
firebase emulators:export ./emulator-data
firebase emulators:start --import=./emulator-data
Emulator UI at http://localhost:4000
模拟器UI地址:http://localhost:4000
```json
// firebase.json — emulator config
{
"emulators": {
"auth": { "port": 9099 },
"firestore": { "port": 8080 },
"functions": { "port": 5001 },
"hosting": { "port": 5000 },
"ui": { "enabled": true, "port": 4000 }
}
}
```json
// firebase.json — 模拟器配置
{
"emulators": {
"auth": { "port": 9099 },
"firestore": { "port": 8080 },
"functions": { "port": 5001 },
"hosting": { "port": 5000 },
"ui": { "enabled": true, "port": 4000 }
}
}Environment Configuration
环境配置
bash
undefinedbash
undefinedSet environment variables for functions
为函数设置环境变量
firebase functions:config:set stripe.key="sk_live_xxx" app.name="MyApp"
firebase functions:config:set stripe.key="sk_live_xxx" app.name="MyApp"
View config
查看配置
firebase functions:config:get
firebase functions:config:get
Use in functions (v1)
在函数中使用(v1版本)
const stripeKey = functions.config().stripe.key;
const stripeKey = functions.config().stripe.key;
For v2 functions, use .env files
对于v2函数,使用.env文件
functions/.env
functions/.env
STRIPE_KEY=sk_live_xxx
STRIPE_KEY=sk_live_xxx
functions/.env.local (for emulators)
functions/.env.local(用于模拟器)
STRIPE_KEY=sk_test_xxx
undefinedSTRIPE_KEY=sk_test_xxx
undefinedMulti-Environment Setup
多环境设置
bash
undefinedbash
undefinedCreate separate projects for each environment
为每个环境创建独立项目
firebase use --add # Add staging project alias
firebase use staging # Switch to staging
firebase use production
firebase use --add # 添加预发布项目别名
firebase use staging # 切换到预发布环境
firebase use production
Deploy to specific project
部署到特定项目
firebase deploy --project my-app-staging
firebase deploy --project my-app-production
firebase deploy --project my-app-staging
firebase deploy --project my-app-production
.firebaserc
.firebaserc
{
"projects": {
"staging": "my-app-staging",
"production": "my-app-production"
}
}
undefined{
"projects": {
"staging": "my-app-staging",
"production": "my-app-production"
}
}
undefinedCLI Reference
CLI参考
bash
firebase projects:list # List all projects
firebase deploy # Deploy everything
firebase deploy --only functions # Deploy only functions
firebase deploy --only hosting # Deploy only hosting
firebase deploy --only firestore # Deploy rules + indexes
firebase functions:log # View function logs
firebase hosting:channel:create pr-123 # Preview channel
firebase hosting:channel:delete pr-123bash
firebase projects:list # 列出所有项目
firebase deploy # 部署所有服务
firebase deploy --only functions # 仅部署函数
firebase deploy --only hosting # 仅托管部署
firebase deploy --only firestore # 部署规则和索引
firebase functions:log # 查看函数日志
firebase hosting:channel:create pr-123 # 创建预览频道
firebase hosting:channel:delete pr-123Security Best Practices
安全最佳实践
- Write strict Firestore security rules before any other code
- Separate environments by Firebase project (staging/production)
- Enable budget alerts and quota monitoring in GCP console
- Move privileged logic into Cloud Functions (never trust the client)
- Use App Check to prevent API abuse from non-app clients
- Enable Firestore audit logging for compliance
- Review OAuth consent screen settings
- 在编写任何其他代码之前,先编写严格的Firestore安全规则
- 通过Firebase项目分离环境(预发布/生产)
- 在GCP控制台中启用预算警报和配额监控
- 将特权逻辑移至Cloud Functions(绝不信任客户端)
- 使用App Check防止非应用客户端滥用API
- 启用Firestore审计日志以符合合规要求
- 审核OAuth同意屏幕设置
Troubleshooting
故障排除
| Issue | Solution |
|---|---|
| Permission denied | Check Firestore rules, verify auth state |
| Function cold starts | Use min instances ( |
| Emulator won't start | Check port conflicts, run |
| Deploy fails | Run |
| Rules test failing | Use |
| 问题 | 解决方案 |
|---|---|
| 权限被拒绝 | 检查Firestore规则,验证认证状态 |
| 函数冷启动 | 使用最小实例数( |
| 模拟器无法启动 | 检查端口冲突,运行 |
| 部署失败 | 运行 |
| 规则测试失败 | 使用 |
Related Skills
相关技能
- gcp-cloud-functions — Function runtime patterns
- vercel-deployments — Alternative frontend hosting
- convex-backend — Alternative managed backend
- gcp-cloud-functions — 函数运行时模式
- vercel-deployments — 替代前端托管方案
- convex-backend — 替代托管后端方案