Google's Backend-as-a-Service Platform
Firebase steht für Googles umfassende Backend-as-a-Service-Plattform (BaaS) wurde entwickelt, um die Anwendungsentwicklung zu beschleunigen, indem eine Suite mit Cloud-basierten Tools und Services bereitgestellt wird. Ursprünglich von Firebase Inc. entwickelt und von Google im Jahr 2014 erworben, hat sich Firebase zu einer kompletten Entwicklungsplattform entwickelt, die Backend-Infrastruktur, Echtzeit-Datensynchronisation, Authentifizierung, Hosting, Analytik und vieles mehr behandelt. Firebase bietet zwei primäre Datenbanklösungen: die ursprüngliche Realtime-Datenbank und die fortschrittlichere Cloud Firestore, die beide für Echtzeitanwendungen mit Offline-Funktionen und nahtloser Synchronisation über mehrere Clients konzipiert sind.
Erste Schritte mit Firebase
Projektaufbau und Konfiguration
```javascript // Install Firebase CLI npm install -g firebase-tools
// Login to Firebase firebase login
// Initialize Firebase project firebase init
// Install Firebase SDK for web npm install firebase
// Initialize Firebase in your application import \\{ initializeApp \\} from 'firebase/app'; import \\{ getFirestore \\} from 'firebase/firestore'; import \\{ getAuth \\} from 'firebase/auth'; import \\{ getStorage \\} from 'firebase/storage';
const firebaseConfig = \\{ apiKey: "your-api-key", authDomain: "your-project.firebaseapp.com", databaseURL: "https://your-project-default-rtdb.firebaseio.com", projectId: "your-project-id", storageBucket: "your-project.appspot.com", messagingSenderId: "123456789", appId: "your-app-id" \\};
// Initialize Firebase const app = initializeApp(firebaseConfig);
// Initialize services const db = getFirestore(app); const auth = getAuth(app); const storage = getStorage(app);
export \\{ db, auth, storage \\}; ```_
Firebase Console und Projektmanagement
```javascript // Firebase project structure // - Authentication: User management and sign-in // - Firestore Database: NoSQL document database // - Realtime Database: JSON tree database // - Storage: File storage service // - Hosting: Web hosting service // - Functions: Serverless functions // - Analytics: App usage analytics // - Performance: App performance monitoring
// Environment configuration // Development const devConfig = \\{ apiKey: "dev-api-key", authDomain: "dev-project.firebaseapp.com", projectId: "dev-project-id" \\};
// Production const prodConfig = \\{ apiKey: "prod-api-key", authDomain: "prod-project.firebaseapp.com", projectId: "prod-project-id" \\};
const config = process.env.NODE_ENV === 'production' ? prodConfig : devConfig; const app = initializeApp(config); ```_
Cloud Firestore (empfohlen)
Datenbankstruktur und Sammlungen
```javascript // Firestore data model: Collections -> Documents -> Fields // Collections contain documents // Documents contain fields and subcollections // Documents are identified by unique IDs
import \\{ collection, doc, addDoc, setDoc, getDoc, getDocs, updateDoc, deleteDoc, query, where, orderBy, limit, onSnapshot \\} from 'firebase/firestore';
// Reference to a collection const usersRef = collection(db, 'users');
// Reference to a specific document const userRef = doc(db, 'users', 'user123');
// Reference to a subcollection const postsRef = collection(db, 'users', 'user123', 'posts');
// Create document with auto-generated ID const createUser = async (userData) => \\{ try \\{ const docRef = await addDoc(collection(db, 'users'), \\{ name: userData.name, email: userData.email, createdAt: new Date(), isActive: true, profile: \\{ | bio: userData.bio | | '', | | avatar: userData.avatar | | '', | preferences: \\{ theme: 'light', notifications: true \\} \\} \\}); console.log('Document written with ID: ', docRef.id); return docRef.id; \\} catch (error) \\{ console.error('Error adding document: ', error); throw error; \\} \\};
// Create document with custom ID const createUserWithId = async (userId, userData) => \\{ try \\{ await setDoc(doc(db, 'users', userId), \\{ name: userData.name, email: userData.email, createdAt: new Date(), isActive: true \\}); console.log('Document created with custom ID: ', userId); \\} catch (error) \\{ console.error('Error creating document: ', error); throw error; \\} \\}; ```_
AUSRÜSTUNG Operationen
```javascript // CREATE - Add documents const addPost = async (userId, postData) => \\{ try \\{ const postRef = await addDoc(collection(db, 'users', userId, 'posts'), \\{ title: postData.title, content: postData.content, | tags: postData.tags | | [], | publishedAt: new Date(), isPublished: false, likes: 0, comments: [] \\}); return postRef.id; \\} catch (error) \\{ console.error('Error adding post: ', error); throw error; \\} \\};
// READ - Get single document const getUser = async (userId) => \\{ try \\{ const docSnap = await getDoc(doc(db, 'users', userId));
if (docSnap.exists()) \\\\{
return \\\\{ id: docSnap.id, ...docSnap.data() \\\\};
\\\\} else \\\\{
console.log('No such document!');
return null;
\\\\}
\\} catch (error) \\{ console.error('Error getting document: ', error); throw error; \\} \\};
// READ - Get multiple documents const getAllUsers = async () => \\{ try \\{ const querySnapshot = await getDocs(collection(db, 'users')); const users = [];
querySnapshot.forEach((doc) => \\\\{
users.push(\\\\{ id: doc.id, ...doc.data() \\\\});
\\\\});
return users;
\\} catch (error) \\{ console.error('Error getting documents: ', error); throw error; \\} \\};
// UPDATE - Update document const updateUser = async (userId, updates) => \\{ try \\{ const userRef = doc(db, 'users', userId); await updateDoc(userRef, \\{ ...updates, updatedAt: new Date() \\}); console.log('Document updated successfully'); \\} catch (error) \\{ console.error('Error updating document: ', error); throw error; \\} \\};
// UPDATE - Update nested fields const updateUserProfile = async (userId, profileUpdates) => \\{ try \\{ const userRef = doc(db, 'users', userId); await updateDoc(userRef, \\{ 'profile.bio': profileUpdates.bio, 'profile.avatar': profileUpdates.avatar, 'profile.preferences.theme': profileUpdates.theme, updatedAt: new Date() \\}); \\} catch (error) \\{ console.error('Error updating profile: ', error); throw error; \\} \\};
// DELETE - Delete document const deleteUser = async (userId) => \\{ try \\{ await deleteDoc(doc(db, 'users', userId)); console.log('Document deleted successfully'); \\} catch (error) \\{ console.error('Error deleting document: ', error); throw error; \\} \\}; ```_
Abfrage und Filterung
```javascript import \\{ query, where, orderBy, limit, startAt, endAt, startAfter, endBefore \\} from 'firebase/firestore';
// Simple queries const getActiveUsers = async () => \\{ const q = query( collection(db, 'users'), where('isActive', '==', true) );
const querySnapshot = await getDocs(q); return querySnapshot.docs.map(doc => (\\{ id: doc.id, ...doc.data() \\})); \\};
// Compound queries const getRecentActivePosts = async () => \\{ const q = query( collection(db, 'posts'), where('isPublished', '==', true), where('publishedAt', '>', new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)), orderBy('publishedAt', 'desc'), limit(10) );
const querySnapshot = await getDocs(q); return querySnapshot.docs.map(doc => (\\{ id: doc.id, ...doc.data() \\})); \\};
// Array queries const getPostsByTags = async (tags) => \\{ const q = query( collection(db, 'posts'), where('tags', 'array-contains-any', tags) );
const querySnapshot = await getDocs(q); return querySnapshot.docs.map(doc => (\\{ id: doc.id, ...doc.data() \\})); \\};
// Range queries const getUsersByAgeRange = async (minAge, maxAge) => \\{ const q = query( collection(db, 'users'), where('age', '>=', minAge), where('age', '<=', maxAge), orderBy('age') );
const querySnapshot = await getDocs(q); return querySnapshot.docs.map(doc => (\\{ id: doc.id, ...doc.data() \\})); \\};
// Pagination const getPaginatedUsers = async (pageSize = 10, lastDoc = null) => \\{ let q = query( collection(db, 'users'), orderBy('createdAt', 'desc'), limit(pageSize) );
if (lastDoc) \\{ q = query( collection(db, 'users'), orderBy('createdAt', 'desc'), startAfter(lastDoc), limit(pageSize) ); \\}
const querySnapshot = await getDocs(q); const users = querySnapshot.docs.map(doc => (\\{ id: doc.id, ...doc.data() \\})); const lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
return \\{ users, lastDoc: lastVisible, hasMore: users.length === pageSize \\}; \\};
// Text search (limited - consider Algolia for full-text search) const searchUsersByName = async (searchTerm) => \\{ const q = query( collection(db, 'users'), where('name', '>=', searchTerm), where('name', '<=', searchTerm + '\uf8ff'), orderBy('name'), limit(10) );
const querySnapshot = await getDocs(q); return querySnapshot.docs.map(doc => (\\{ id: doc.id, ...doc.data() \\})); \\}; ```_
Hörer in Echtzeit
```javascript // Real-time listener for single document const subscribeToUser = (userId, callback) => \\{ const userRef = doc(db, 'users', userId);
const unsubscribe = onSnapshot(userRef, (doc) => \\{ if (doc.exists()) \\{ callback(\\{ id: doc.id, ...doc.data() \\}); \\} else \\{ callback(null); \\} \\}, (error) => \\{ console.error('Error listening to user: ', error); \\});
return unsubscribe; // Call this function to stop listening \\};
// Real-time listener for collection const subscribeToActiveUsers = (callback) => \\{ const q = query( collection(db, 'users'), where('isActive', '==', true), orderBy('createdAt', 'desc') );
const unsubscribe = onSnapshot(q, (querySnapshot) => \\{ const users = []; querySnapshot.forEach((doc) => \\{ users.push(\\{ id: doc.id, ...doc.data() \\}); \\}); callback(users); \\}, (error) => \\{ console.error('Error listening to users: ', error); \\});
return unsubscribe; \\};
// Listen to document changes with metadata const subscribeToUserWithMetadata = (userId, callback) => \\{ const userRef = doc(db, 'users', userId);
const unsubscribe = onSnapshot(userRef, \\{ includeMetadataChanges: true \\}, (doc) => \\{ const source = doc.metadata.hasPendingWrites ? 'Local' : 'Server'; const data = doc.exists() ? \\{ id: doc.id, ...doc.data() \\} : null;
callback(\\\\{ data, source, fromCache: doc.metadata.fromCache \\\\});
\\});
return unsubscribe; \\};
// React hook example for real-time data const useUser = (userId) => \\{ const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null);
useEffect(() => \\{ if (!userId) \\{ setUser(null); setLoading(false); return; \\}
const unsubscribe = subscribeToUser(userId, (userData) => \\\\{
setUser(userData);
setLoading(false);
setError(null);
\\\\});
return () => unsubscribe();
\\}, [userId]);
return \\{ user, loading, error \\}; \\}; ```_
Transaktionen und Batch-Operationen
```javascript import \\{ runTransaction, writeBatch, increment, arrayUnion, arrayRemove, serverTimestamp \\} from 'firebase/firestore';
// Transaction example - Transfer points between users const transferPoints = async (fromUserId, toUserId, points) => \\{ try \\{ await runTransaction(db, async (transaction) => \\{ const fromUserRef = doc(db, 'users', fromUserId); const toUserRef = doc(db, 'users', toUserId);
const fromUserDoc = await transaction.get(fromUserRef);
const toUserDoc = await transaction.get(toUserRef);
| if (!fromUserDoc.exists() | | !toUserDoc.exists()) \\{ | throw new Error('One or both users do not exist'); \\}
| const fromUserPoints = fromUserDoc.data().points | | 0; |
if (fromUserPoints < points) \\\\{
throw new Error('Insufficient points');
\\\\}
transaction.update(fromUserRef, \\\\{
points: fromUserPoints - points,
updatedAt: serverTimestamp()
\\\\});
transaction.update(toUserRef, \\\\{
points: increment(points),
updatedAt: serverTimestamp()
\\\\});
\\\\});
console.log('Points transferred successfully');
\\} catch (error) \\{ console.error('Transaction failed: ', error); throw error; \\} \\};
// Batch operations const batchUpdateUsers = async (userUpdates) => \\{ const batch = writeBatch(db);
userUpdates.forEach((\\{ userId, updates \\}) => \\{ const userRef = doc(db, 'users', userId); batch.update(userRef, \\{ ...updates, updatedAt: serverTimestamp() \\}); \\});
try \\{ await batch.commit(); console.log('Batch update completed'); \\} catch (error) \\{ console.error('Batch update failed: ', error); throw error; \\} \\};
// Array operations const addTagToPost = async (postId, tag) => \\{ const postRef = doc(db, 'posts', postId); await updateDoc(postRef, \\{ tags: arrayUnion(tag), updatedAt: serverTimestamp() \\}); \\};
const removeTagFromPost = async (postId, tag) => \\{ const postRef = doc(db, 'posts', postId); await updateDoc(postRef, \\{ tags: arrayRemove(tag), updatedAt: serverTimestamp() \\}); \\};
// Increment/decrement operations const likePost = async (postId) => \\{ const postRef = doc(db, 'posts', postId); await updateDoc(postRef, \\{ likes: increment(1), updatedAt: serverTimestamp() \\}); \\}; ```_
Firebase Realtime Datenbank
Datenbankstruktur und Referenzen
```javascript import \\{ getDatabase, ref, set, get, push, update, remove, on, off, child, orderByChild, orderByKey, orderByValue, limitToFirst, limitToLast, startAt, endAt, equalTo \\} from 'firebase/database';
// Initialize Realtime Database const rtdb = getDatabase();
// Database structure (JSON tree) // \\{ // "users": \\{ // "user1": \\{ // "name": "John Doe", // "email": "john@example.com", // "posts": \\{ // "post1": true, // "post2": true // \\} // \\} // \\}, // "posts": \\{ // "post1": \\{ // "title": "First Post", // "content": "Hello World", // "author": "user1", // "timestamp": 1642694400000 // \\} // \\} // \\}
// Create references const usersRef = ref(rtdb, 'users'); const userRef = ref(rtdb, 'users/user1'); const postsRef = ref(rtdb, 'posts'); ```_
AUSRÜSTUNG Operationen in Echtzeit-Datenbank
``javascript
// CREATE/UPDATE - Set data
const createUser = async (userId, userData) => \\\\{
try \\\\{
await set(ref(rtdb,
users/$\{userId\}`), \\{
name: userData.name,
email: userData.email,
createdAt: Date.now(),
isActive: true
\\});
console.log('User created successfully');
\\} catch (error) \\{
console.error('Error creating user: ', error);
throw error;
\\}
\\};
// CREATE - Push data (auto-generated key) const addPost = async (postData) => \\{ try \\{ const newPostRef = push(ref(rtdb, 'posts')); await set(newPostRef, \\{ title: postData.title, content: postData.content, author: postData.author, timestamp: Date.now(), likes: 0 \\}); return newPostRef.key; \\} catch (error) \\{ console.error('Error adding post: ', error); throw error; \\} \\};
// READ - Get data once
const getUser = async (userId) => \\{
try \\{
const snapshot = await get(ref(rtdb, users/$\\{userId\\}
));
if (snapshot.exists()) \\{
return \\{ id: userId, ...snapshot.val() \\};
\\} else \\{
console.log('No data available');
return null;
\\}
\\} catch (error) \\{
console.error('Error getting user: ', error);
throw error;
\\}
\\};
// READ - Get all users const getAllUsers = async () => \\{ try \\{ const snapshot = await get(ref(rtdb, 'users')); if (snapshot.exists()) \\{ const users = []; snapshot.forEach((childSnapshot) => \\{ users.push(\\{ id: childSnapshot.key, ...childSnapshot.val() \\}); \\}); return users; \\} else \\{ return []; \\} \\} catch (error) \\{ console.error('Error getting users: ', error); throw error; \\} \\};
// UPDATE - Update specific fields
const updateUser = async (userId, updates) => \\{
try \\{
await update(ref(rtdb, users/$\\{userId\\}
), \\{
...updates,
updatedAt: Date.now()
\\});
console.log('User updated successfully');
\\} catch (error) \\{
console.error('Error updating user: ', error);
throw error;
\\}
\\};
// DELETE - Remove data
const deleteUser = async (userId) => \\{
try \\{
await remove(ref(rtdb, users/$\\{userId\\}
));
console.log('User deleted successfully');
\\} catch (error) \\{
console.error('Error deleting user: ', error);
throw error;
\\}
\\};
```_
Echtzeit-Anhörer und Queries
``javascript
// Real-time listener
const subscribeToUser = (userId, callback) => \\\\{
const userRef = ref(rtdb,
users/$\{userId\}`);
const unsubscribe = on(userRef, 'value', (snapshot) => \\{ const data = snapshot.exists() ? \\{ id: userId, ...snapshot.val() \\} : null; callback(data); \\}, (error) => \\{ console.error('Error listening to user: ', error); \\});
return () => off(userRef, 'value', unsubscribe); \\};
// Listen to child events
const subscribeToUserPosts = (userId, callbacks) => \\{
const userPostsRef = ref(rtdb, users/$\\{userId\\}/posts
);
const childAddedListener = on(userPostsRef, 'child_added', callbacks.onAdded); const childChangedListener = on(userPostsRef, 'child_changed', callbacks.onChanged); const childRemovedListener = on(userPostsRef, 'child_removed', callbacks.onRemoved);
return () => \\{ off(userPostsRef, 'child_added', childAddedListener); off(userPostsRef, 'child_changed', childChangedListener); off(userPostsRef, 'child_removed', childRemovedListener); \\}; \\};
// Queries with ordering and filtering const getTopPosts = async (limit = 10) => \\{ try \\{ const topPostsQuery = query( ref(rtdb, 'posts'), orderByChild('likes'), limitToLast(limit) );
const snapshot = await get(topPostsQuery);
const posts = [];
snapshot.forEach((childSnapshot) => \\\\{
posts.unshift(\\\\{
id: childSnapshot.key,
...childSnapshot.val()
\\\\});
\\\\});
return posts;
\\} catch (error) \\{ console.error('Error getting top posts: ', error); throw error; \\} \\};
// Range queries const getPostsByDateRange = async (startDate, endDate) => \\{ try \\{ const dateRangeQuery = query( ref(rtdb, 'posts'), orderByChild('timestamp'), startAt(startDate), endAt(endDate) );
const snapshot = await get(dateRangeQuery);
const posts = [];
snapshot.forEach((childSnapshot) => \\\\{
posts.push(\\\\{
id: childSnapshot.key,
...childSnapshot.val()
\\\\});
\\\\});
return posts;
\\} catch (error) \\{ console.error('Error getting posts by date range: ', error); throw error; \\} \\};
// Equal to query const getUsersByStatus = async (status) => \\{ try \\{ const statusQuery = query( ref(rtdb, 'users'), orderByChild('status'), equalTo(status) );
const snapshot = await get(statusQuery);
const users = [];
snapshot.forEach((childSnapshot) => \\\\{
users.push(\\\\{
id: childSnapshot.key,
...childSnapshot.val()
\\\\});
\\\\});
return users;
\\} catch (error) \\{ console.error('Error getting users by status: ', error); throw error; \\} \\}; ```_
Firebase Authentication
Authentication Setup und Methoden
```javascript import \\{ getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword, signInWithPopup, GoogleAuthProvider, FacebookAuthProvider, TwitterAuthProvider, signOut, onAuthStateChanged, updateProfile, updatePassword, sendPasswordResetEmail, deleteUser \\} from 'firebase/auth';
const auth = getAuth();
// Email/Password Authentication const signUpWithEmail = async (email, password, displayName) => \\{ try \\{ const userCredential = await createUserWithEmailAndPassword(auth, email, password); const user = userCredential.user;
// Update user profile
await updateProfile(user, \\\\{
displayName: displayName
\\\\});
// Create user document in Firestore
await setDoc(doc(db, 'users', user.uid), \\\\{
email: user.email,
displayName: displayName,
createdAt: new Date(),
isActive: true
\\\\});
return user;
\\} catch (error) \\{ console.error('Error signing up: ', error); throw error; \\} \\};
const signInWithEmail = async (email, password) => \\{ try \\{ const userCredential = await signInWithEmailAndPassword(auth, email, password); return userCredential.user; \\} catch (error) \\{ console.error('Error signing in: ', error); throw error; \\} \\};
// Social Authentication const signInWithGoogle = async () => \\{ try \\{ const provider = new GoogleAuthProvider(); provider.addScope('profile'); provider.addScope('email');
const result = await signInWithPopup(auth, provider);
const user = result.user;
// Check if user document exists, create if not
const userDoc = await getDoc(doc(db, 'users', user.uid));
if (!userDoc.exists()) \\\\{
await setDoc(doc(db, 'users', user.uid), \\\\{
email: user.email,
displayName: user.displayName,
photoURL: user.photoURL,
provider: 'google',
createdAt: new Date(),
isActive: true
\\\\});
\\\\}
return user;
\\} catch (error) \\{ console.error('Error signing in with Google: ', error); throw error; \\} \\};
// Authentication state observer const useAuthState = () => \\{ const [user, setUser] = useState(null); const [loading, setLoading] = useState(true);
useEffect(() => \\{ const unsubscribe = onAuthStateChanged(auth, (user) => \\{ setUser(user); setLoading(false); \\});
return () => unsubscribe();
\\}, []);
return \\{ user, loading \\}; \\};
// Sign out const signOutUser = async () => \\{ try \\{ await signOut(auth); console.log('User signed out successfully'); \\} catch (error) \\{ console.error('Error signing out: ', error); throw error; \\} \\};
// Password reset const resetPassword = async (email) => \\{ try \\{ await sendPasswordResetEmail(auth, email); console.log('Password reset email sent'); \\} catch (error) \\{ console.error('Error sending password reset email: ', error); throw error; \\} \\};
// Update user profile const updateUserProfile = async (updates) => \\{ try \\{ const user = auth.currentUser; if (user) \\{ await updateProfile(user, updates);
// Also update Firestore document
await updateDoc(doc(db, 'users', user.uid), \\\\{
...updates,
updatedAt: new Date()
\\\\});
\\\\}
\\} catch (error) \\{ console.error('Error updating profile: ', error); throw error; \\} \\}; ```_
Sicherheitsregeln
```javascript // Firestore Security Rules // rules_version = '2'; // service cloud.firestore \\{ // match /databases/\\{database\\}/documents \\{ // // Users can read and write their own data // match /users/\\{userId\\} \\{ // allow read, write: if request.auth != null && request.auth.uid == userId; // \\} // // // Posts are readable by all authenticated users // // Only the author can write/update/delete // match /posts/\\{postId\\} \\{ // allow read: if request.auth != null; // allow create: if request.auth != null && // request.auth.uid == resource.data.authorId; // allow update, delete: if request.auth != null && // request.auth.uid == resource.data.authorId; // \\} // // // Comments can be created by authenticated users // // Only the author can update/delete their comments // match /posts/\\{postId\\}/comments/\\{commentId\\} \\{ // allow read: if request.auth != null; // allow create: if request.auth != null; // allow update, delete: if request.auth != null && // request.auth.uid == resource.data.authorId; // \\} // \\} // \\}
// Realtime Database Security Rules // \\{ // "rules": \\{ // "users": \\{ // "$uid": \\{ // ".read": "$uid === auth.uid", // ".write": "$uid === auth.uid" // \\} // \\}, // "posts": \\{ // ".read": "auth != null", // "$postId": \\{ // ".write": "auth != null && ( | // !data.exists() | | | // data.child('authorId').val() === auth.uid // )" // \\} // \\} // \\} // \\}
// Custom claims for role-based access const setUserRole = async (uid, role) => \\{ // This would be done in a Cloud Function with Admin SDK // admin.auth().setCustomUserClaims(uid, \\{ role: role \\}); \\};
// Check user role in security rules // allow write: if request.auth.token.role == 'admin'; ```_
Firebase Speicher
Datei Hochladen und Management
```javascript import \\{ getStorage, ref as storageRef, uploadBytes, uploadBytesResumable, getDownloadURL, deleteObject, listAll, getMetadata, updateMetadata \\} from 'firebase/storage';
const storage = getStorage();
// Upload file const uploadFile = async (file, path) => \\{ try \\{ const fileRef = storageRef(storage, path); const snapshot = await uploadBytes(fileRef, file); const downloadURL = await getDownloadURL(snapshot.ref);
console.log('File uploaded successfully');
return \\\\{ downloadURL, fullPath: snapshot.ref.fullPath \\\\};
\\} catch (error) \\{ console.error('Error uploading file: ', error); throw error; \\} \\};
// Upload with progress tracking const uploadFileWithProgress = (file, path, onProgress) => \\{ return new Promise((resolve, reject) => \\{ const fileRef = storageRef(storage, path); const uploadTask = uploadBytesResumable(fileRef, file);
uploadTask.on('state_changed',
(snapshot) => \\\\{
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
onProgress(progress);
\\\\},
(error) => \\\\{
console.error('Upload error: ', error);
reject(error);
\\\\},
async () => \\\\{
try \\\\{
const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
resolve(\\\\{ downloadURL, fullPath: uploadTask.snapshot.ref.fullPath \\\\});
\\\\} catch (error) \\\\{
reject(error);
\\\\}
\\\\}
);
\\}); \\};
// Upload user avatar
const uploadUserAvatar = async (userId, file) => \\{
try \\{
const path = avatars/$\\{userId\\}/$\\{file.name\\}
;
const result = await uploadFile(file, path);
// Update user profile with avatar URL
await updateDoc(doc(db, 'users', userId), \\\\{
photoURL: result.downloadURL,
updatedAt: new Date()
\\\\});
return result.downloadURL;
\\} catch (error) \\{ console.error('Error uploading avatar: ', error); throw error; \\} \\};
// Delete file const deleteFile = async (filePath) => \\{ try \\{ const fileRef = storageRef(storage, filePath); await deleteObject(fileRef); console.log('File deleted successfully'); \\} catch (error) \\{ console.error('Error deleting file: ', error); throw error; \\} \\};
// List files in directory const listFiles = async (path) => \\{ try \\{ const listRef = storageRef(storage, path); const result = await listAll(listRef);
const files = await Promise.all(
result.items.map(async (itemRef) => \\\\{
const url = await getDownloadURL(itemRef);
const metadata = await getMetadata(itemRef);
return \\\\{
name: itemRef.name,
fullPath: itemRef.fullPath,
downloadURL: url,
size: metadata.size,
contentType: metadata.contentType,
timeCreated: metadata.timeCreated
\\\\};
\\\\})
);
return files;
\\} catch (error) \\{ console.error('Error listing files: ', error); throw error; \\} \\}; ```_
Firebase Cloud Funktionen
Funktion Entwicklung und Bereitstellung
```javascript // Install Firebase Functions // npm install -g firebase-tools // firebase init functions
// functions/index.js const functions = require('firebase-functions'); const admin = require('firebase-admin');
admin.initializeApp();
// HTTP Cloud Function exports.helloWorld = functions.https.onRequest((request, response) => \\{ response.send('Hello from Firebase!'); \\});
// Firestore Trigger exports.onUserCreate = functions.firestore .document('users/\\{userId\\}') .onCreate(async (snap, context) => \\{ const userData = snap.data(); const userId = context.params.userId;
// Send welcome email
console.log(`New user created: $\\{userData.email\\}`);
// Create user stats document
await admin.firestore().collection('userStats').doc(userId).set(\\\\{
postsCount: 0,
likesReceived: 0,
joinedAt: admin.firestore.FieldValue.serverTimestamp()
\\\\});
\\});
// Scheduled Function exports.dailyCleanup = functions.pubsub .schedule('0 2 * * *') // Every day at 2 AM .timeZone('America/New_York') .onRun(async (context) => \\{ // Clean up old data const cutoffDate = new Date(); cutoffDate.setDate(cutoffDate.getDate() - 30);
const oldPosts = await admin.firestore()
.collection('posts')
.where('createdAt', '<', cutoffDate)
.where('isDeleted', '==', true)
.get();
const batch = admin.firestore().batch();
oldPosts.docs.forEach(doc => \\\\{
batch.delete(doc.ref);
\\\\});
await batch.commit();
console.log(`Deleted $\\{oldPosts.size\\} old posts`);
\\});
// Callable Function exports.addAdminRole = functions.https.onCall(async (data, context) => \\{ // Check if user is authenticated and is admin if (!context.auth) \\{ throw new functions.https.HttpsError('unauthenticated', 'User must be authenticated'); \\}
if (!context.auth.token.admin) \\{ throw new functions.https.HttpsError('permission-denied', 'User must be admin'); \\}
try \\{ await admin.auth().setCustomUserClaims(data.uid, \\{ admin: true \\}); return \\{ message: 'Admin role added successfully' \\}; \\} catch (error) \\{ throw new functions.https.HttpsError('internal', 'Error adding admin role'); \\} \\});
// Deploy functions // firebase deploy --only functions ```_
Leistungsoptimierung und Best Practices
Datenmodellierung Best Practices
```javascript // Firestore data modeling principles
// 1. Denormalization for read efficiency const createPostWithAuthor = async (postData, authorData) => \\{ const postRef = await addDoc(collection(db, 'posts'), \\{ title: postData.title, content: postData.content, // Denormalize author data for efficient reads author: \\{ id: authorData.id, name: authorData.name, avatar: authorData.avatar \\}, createdAt: new Date(), likes: 0, commentsCount: 0 \\});
return postRef.id; \\};
// 2. Use subcollections for one-to-many relationships const addCommentToPost = async (postId, commentData) => \\{ const commentRef = await addDoc( collection(db, 'posts', postId, 'comments'), \\{ content: commentData.content, author: commentData.author, createdAt: new Date(), likes: 0 \\} );
// Update comment count in parent post await updateDoc(doc(db, 'posts', postId), \\{ commentsCount: increment(1) \\});
return commentRef.id; \\};
// 3. Use arrays for small lists, subcollections for large lists const addTagToPost = async (postId, tag) => \\{ await updateDoc(doc(db, 'posts', postId), \\{ tags: arrayUnion(tag) \\}); \\};
// 4. Optimize for your queries // Create composite indexes for compound queries // Index: collection: posts, fields: isPublished ASC, createdAt DESC
const getPublishedPosts = async () => \\{ const q = query( collection(db, 'posts'), where('isPublished', '==', true), orderBy('createdAt', 'desc'), limit(20) );
return await getDocs(q); \\}; ```_
Caching und Offline Support
```javascript import \\{ enableNetwork, disableNetwork \\} from 'firebase/firestore';
// Enable offline persistence import \\{ initializeFirestore, persistentLocalCache \\} from 'firebase/firestore';
const db = initializeFirestore(app, \\{ localCache: persistentLocalCache() \\});
// Handle online/offline state const handleNetworkChange = async (isOnline) => \\{ try \\{ if (isOnline) \\{ await enableNetwork(db); console.log('Network enabled'); \\} else \\{ await disableNetwork(db); console.log('Network disabled'); \\} \\} catch (error) \\{ console.error('Error changing network state: ', error); \\} \\};
// Listen for network changes window.addEventListener('online', () => handleNetworkChange(true)); window.addEventListener('offline', () => handleNetworkChange(false));
// Cache management const getCachedData = async (docRef) => \\{ try \\{ // Try to get from cache first const cachedDoc = await getDoc(docRef, \\{ source: 'cache' \\}); if (cachedDoc.exists()) \\{ return \\{ data: cachedDoc.data(), fromCache: true \\}; \\} \\} catch (error) \\{ console.log('No cached data available'); \\}
// Fallback to server const serverDoc = await getDoc(docRef, \\{ source: 'server' \\}); return \\{ data: serverDoc.exists() ? serverDoc.data() : null, fromCache: false \\}; \\}; ```_
Sicherheits- und Leistungsüberwachung
```javascript // Performance monitoring import \\{ getPerformance, trace \\} from 'firebase/performance';
const perf = getPerformance(app);
// Custom trace const measureDatabaseOperation = async (operation) => \\{ const customTrace = trace(perf, 'database_operation'); customTrace.start();
try \\{ const result = await operation(); customTrace.putAttribute('success', 'true'); return result; \\} catch (error) \\{ customTrace.putAttribute('success', 'false'); customTrace.putAttribute('error', error.message); throw error; \\} finally \\{ customTrace.stop(); \\} \\};
// Usage const getUserWithTrace = async (userId) => \\{ return await measureDatabaseOperation(async () => \\{ return await getDoc(doc(db, 'users', userId)); \\}); \\};
// Analytics import \\{ getAnalytics, logEvent \\} from 'firebase/analytics';
const analytics = getAnalytics(app);
// Log custom events const logUserAction = (action, parameters = \\{\\}) => \\{ logEvent(analytics, action, \\{ ...parameters, timestamp: Date.now() \\}); \\};
// Usage logUserAction('post_created', \\{ post_id: 'post123', category: 'technology' \\}); ```_
Firebase bietet Entwicklern eine leistungsstarke Plattform für den Aufbau moderner, skalierbarer Anwendungen mit Echtzeit-Funktionen, robuster Authentifizierung und nahtloser Offline-Unterstützung. Die Integration mit der Google Cloud Platform und der umfangreichen SDK-Unterstützung auf mehreren Plattformen macht es zu einer exzellenten Wahl für die schnelle Anwendungsentwicklung, von einfachen Prototypen bis hin zu komplexen, produktionsbereiten Anwendungen, die Millionen von Nutzern bedienen.