Découvrir Firebase pour construire un backend sans serveur. Authentification, Firestore, Storage et déploiement hosting avec Firebase.
Introduction à Firebase et serverless
Firebase est une plateforme backend complète de Google qui permet de construire des applications sans gérer de serveurs. C'est l'approche serverless : vous écrivez le code, Firebase gère l'infrastructure.
Services Firebase :
- Authentification → Gestion des utilisateurs et tokens
- Firestore → Base de données NoSQL temps réel
- Realtime Database → Alternative NoSQL avec sync temps réel
- Cloud Storage → Stockage de fichiers (images, vidéos)
- Cloud Functions → Serverless computing pour votre logique métier
- Hosting → Déployer votre app statique avec CDN
- Analytics → Tracking d'événements utilisateurs
Avantages Firebase :
- ✅ Développement ultra-rapide (0 serveur à configurer)
- ✅ Scalabilité automatique (gère la charge)
- ✅ Pricing flexible (payez que ce que vous utilisez)
- ✅ Excellente documentation et SDK
- ✅ PAS de DevOps à gérer
Configuration d'un projet Firebase
Étape 1 : Créer un compte Firebase
- Aller sur
firebase.google.com - Se connecter avec Google (ou créer un compte)
- Cliquer sur "Create a project"
Étape 2 : Initialiser le projet
$ npm install -g firebase-tools
$ firebase login
$ firebase init
# Sélectionner :
# - Realtime Database
# - Firestore
# - Cloud Functions
# - Hosting
# - Emulator
Étape 3 : Structure du projet généré
firebase-project/
├── .firebaserc # Configuration Firebase
├── firebase.json # Configuration du projet
├── firestore.rules # Règles Firestore (sécurité)
├── public/ # Dossier pour Hosting
├── functions/ # Cloud Functions
│ ├── index.js
│ └── package.json
└── .emulator/ # Emulators locaux
Étape 4 : Déployer
$ firebase deploy # Deploy tout
$ firebase deploy --only hosting # Deploy uniquement Hosting
$ firebase deploy --only functions # Deploy uniquement Functions
Authentification Firebase
Setup Authentication :
Dans Firebase Console → Authentication → Enable Email/Password
Inscription et connexion :
import { initializeApp } from 'firebase/app';
import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword } from 'firebase/auth';
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "your-project.firebaseapp.com",
projectId: "your-project",
storageBucket: "your-project.appspot.com",
messagingSenderId: "123456",
appId: "1:123456:web:abc123"
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
// Inscription
const signup = async (email, password) => {
try {
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
return userCredential.user;
} catch (error) {
console.error('Error:', error.message);
}
};
// Connexion
const login = async (email, password) => {
try {
const userCredential = await signInWithEmailAndPassword(auth, email, password);
return userCredential.user;
} catch (error) {
console.error('Error:', error.message);
}
};
Écouter les changements d'authentification :
import { onAuthStateChanged } from 'firebase/auth';
onAuthStateChanged(auth, (user) => {
if (user) {
console.info('Utilisateur connecté :', user.email);
console.info('UID :', user.uid);
} else {
console.info('Utilisateur non connecté');
}
});
Firestore : base de données temps réel
Créer et récupérer des documents :
import { getFirestore, collection, addDoc, getDocs, query, where } from 'firebase/firestore';
const db = getFirestore(app);
// Ajouter un document
const addPost = async (title, content, author) => {
try {
const docRef = await addDoc(collection(db, "posts"), {
title,
content,
author,
createdAt: new Date(),
likes: 0
});
console.info('Document ID:', docRef.id);
} catch (error) {
console.error('Error adding document:', error);
}
};
// Récupérer tous les documents
const getPosts = async () => {
try {
const querySnapshot = await getDocs(collection(db, "posts"));
const posts = [];
querySnapshot.forEach((doc) => {
posts.push({ id: doc.id, ...doc.data() });
});
return posts;
} catch (error) {
console.error('Error:', error);
}
};
// Requête avec filtre
const getPostsByAuthor = async (author) => {
try {
const q = query(collection(db, "posts"), where("author", "==", author));
const querySnapshot = await getDocs(q);
return querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
} catch (error) {
console.error('Error:', error);
}
};
Écoute temps réel (Realtime Listener) :
import { onSnapshot } from 'firebase/firestore';
// S'abonner aux changements en temps réel
onSnapshot(collection(db, "posts"), (snapshot) => {
const posts = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
console.info('Posts updated:', posts);
// Mettre à jour l'UI
});
Mettre à jour et supprimer :
import { updateDoc, deleteDoc, doc } from 'firebase/firestore';
// Mettre à jour
const updatePost = async (postId, updates) => {
await updateDoc(doc(db, "posts", postId), updates);
};
// Supprimer
const deletePost = async (postId) => {
await deleteDoc(doc(db, "posts", postId));
};
Cloud Storage pour les fichiers
Uploader un fichier :
import { getStorage, ref, uploadBytes, getDownloadURL } from 'firebase/storage';
const storage = getStorage(app);
const uploadFile = async (file) => {
try {
const storageRef = ref(storage, `uploads/${file.name}`);
const snapshot = await uploadBytes(storageRef, file);
const downloadUrl = await getDownloadURL(snapshot.ref);
console.info('File available at:', downloadUrl);
return downloadUrl;
} catch (error) {
console.error('Upload error:', error);
}
};
// Utilisation avec un input file
const handleFileUpload = async (event) => {
const file = event.target.files[0];
const url = await uploadFile(file);
};
Afficher une image uploadée :
<input type="file" onChange={handleFileUpload} />
<img id="preview" src="" alt="Uploaded" />
// Dans handleFileUpload :
const url = await uploadFile(file);
document.getElementById('preview').src = url;
Cloud Functions pour la logique serveur
Créer une Cloud Function (Node.js) :
// functions/index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
// HTTP Trigger
exports.helloWorld = functions.https.onRequest((request, response) => {
response.send("Hello from Firebase Cloud Functions!");
});
// Firestore Trigger (sur création de document)
exports.onPostCreated = functions.firestore
.document('posts/{postId}')
.onCreate((snap, context) => {
const post = snap.data();
console.info('Nouveau post créé:', post.title);
// Logique (envoyer email, webhook, etc.)
});
// Callable function depuis le client
exports.addNumbers = functions.https.onCall((data, context) => {
return { result: data.a + data.b };
});
Appeler une function depuis le client :
import { getFunctions, httpsCallable } from 'firebase/functions';
const functions = getFunctions(app);
const addNumbers = httpsCallable(functions, 'addNumbers');
const result = await addNumbers({ a: 5, b: 3 });
console.info(result.data.result); // 8
Firebase Hosting
Déployer une app statique :
$ cd public/
$ npm run build # Générer les fichiers statiques
$ firebase deploy --only hosting
Configuration Firebase Hosting (firebase.json) :
{
"hosting": {
"public": "dist",
"ignore": ["firebase.json", "**/.*"],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
],
"headers": [
{
"source": "/**",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000"
}
]
}
]
}
}
Avantages de Firebase Hosting :
- ✅ CDN global automatique
- ✅ HTTPS par défaut
- ✅ Déploiement en 1 ligne
- ✅ Redirections et headers simplifiés
Intégration avec Angular/React/Vue
React avec Firebase :
import { useEffect, useState } from 'react';
import { collection, onSnapshot } from 'firebase/firestore';
import { db } from './firebase-config';
function PostsList() {
const [posts, setPosts] = useState([]);
useEffect(() => {
const unsubscribe = onSnapshot(collection(db, "posts"), (snapshot) => {
const newPosts = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
setPosts(newPosts);
});
return unsubscribe; // Cleanup
}, []);
return (
<ul>
{posts.map(post => <li key={post.id}>{post.title}</li>)}
</ul>
);
}
Angular avec Firebase :
import { Injectable } from '@angular/core';
import { Firestore, collection, collectionData } from '@angular/fire/firestore';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class PostService {
constructor(private firestore: Firestore) {}
getPosts(): Observable<any> {
const col = collection(this.firestore, 'posts');
return collectionData(col, { idField: 'id' });
}
}
Vue avec Firebase :
import { ref, onMounted } from 'vue';
import { collection, onSnapshot } from 'firebase/firestore';
import { db } from './firebase-config';
export default {
setup() {
const posts = ref([]);
onMounted(() => {
onSnapshot(collection(db, "posts"), (snapshot) => {
posts.value = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}));
});
});
return { posts };
}
}
Performance et bonnes pratiques
Règles de sécurité Firestore (firestore.rules) :
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Permettre lecture/écriture si authentifié
match /posts/{document=**} {
allow read, write: if request.auth != null;
}
// Seulement le propriétaire peut modifier son profil
match /users/{userId} {
allow read, write: if request.auth.uid == userId;
}
// Lecture publique, écriture limitée
match /public/{document=**} {
allow read: if true;
allow write: if request.auth != null && request.auth.uid == request.resource.data.authorId;
}
}
}
Optimisations :
- Indexing : Firebase crée les index automatiquement pour les requêtes
- Pagination : Utiliser
limit()etstartAfter()pour paginer - Offline persistence : Firebase synchronise automatiquement quand la connexion revient
- Batch writes : Regrouper plusieurs écritures pour plus d'efficacité
- Unsubscribe : Ne pas oublier de se désabonner des listeners (memory leaks)
Monitoring et debugging :
$ firebase emulators:start # Émuler localement
$ firebase serve # Tester en local
Comparaison avec alternatives
| Critère | Firebase | Supabase | MongoDB Atlas |
|---|---|---|---|
| Type BD | NoSQL (Firestore) | PostgreSQL | NoSQL (MongoDB) |
| Serverless | ✅ Oui | ⚠️ À configurer | ✅ Atlas |
| Auth intégrée | ✅ Excellent | ✅ Très bon | ❌ À faire soi-même |
| Hosting | ✅ Oui | ❌ Non | ❌ Non |
| Prix (startup) | 💚 Free tier généreux | 💚 Gratuit | ⚠️ Payant |
Quand choisir Firebase :
- ✅ MVP et prototypes rapides
- ✅ Applications avec pics d'utilisation imprévisibles
- ✅ Équipe petite (0 DevOps)
- ✅ Applications temps réel (chat, notifications)
Quand choisir une alternative :
- ❌ Requêtes SQL complexes → PostgreSQL (Supabase)
- ❌ Besoin de contrôle total → VPS classique
- ❌ Application très volumineuse → Infrastructure custom