Si vous avez déjà utilisé le SDK JS Firebase ou d'autres SDK client Firebase, vous connaissez probablement l'interface FirebaseApp et savez comment l'utiliser pour configurer des instances d'application. Pour faciliter des opérations similaires côté serveur, Firebase fournit FirebaseServerApp.
FirebaseServerApp est une variante de FirebaseApp à utiliser dans les environnements de rendu côté serveur (SSR). Il inclut des outils permettant de poursuivre les sessions Firebase qui couvrent la division entre le rendu côté client (CSR) et le rendu côté serveur (SSR). Ces outils et stratégies peuvent vous aider à améliorer les applications Web dynamiques créées avec Firebase et déployées dans des environnements Google tels que Firebase App Hosting.
Utiliser FirebaseServerApp pour :
- Exécutez du code côté serveur dans le contexte de l'utilisateur, contrairement au SDK Admin Firebase, qui dispose de droits d'administration complets.
- Activez l'utilisation d'App Check dans les environnements SSR.
- Poursuivre une session Firebase Auth créée dans le client.
Cycle de vie de FirebaseServerApp
Les frameworks de rendu côté serveur (SSR) et les autres environnements d'exécution non basés sur un navigateur, tels que les travailleurs cloud, optimisent le temps d'initialisation en réutilisant les ressources sur plusieurs exécutions. FirebaseServerApp est conçu pour s'adapter à ces environnements à l'aide d'un mécanisme de comptage de références. Si une application appelle initializeServerApp avec les mêmes paramètres qu'un initializeServerApp précédent, elle reçoit la même instance FirebaseServerApp qui a déjà été initialisée. Cela réduit les coûts d'initialisation et les allocations de mémoire inutiles. Lorsque deleteApp est appelé sur une instance FirebaseServerApp, il réduit le nombre de références, et l'instance est libérée une fois que le nombre de références atteint zéro.
Nettoyage de FirebaseServerApp instances…
Il peut être difficile de savoir quand appeler deleteApp sur une instance FirebaseServerApp, en particulier si vous exécutez de nombreuses opérations asynchrones en parallèle. Le champ releaseOnDeref de FirebaseServerAppSettings permet de simplifier cette opération. Si vous attribuez à releaseOnDeref une référence à un objet dont la durée de vie correspond à la portée de la requête (par exemple, l'objet d'en-tête de la requête SSR), FirebaseServerApp réduira son nombre de références lorsque le framework récupérera l'objet d'en-tête. Cela nettoie automatiquement votre instance FirebaseServerApp.
Voici un exemple d'utilisation de releaseOnDeref :
/// Next.js
import { headers } from 'next/headers'
import { FirebaseServerAppSettings, initializeServerApp} from "firebase/app";
export default async function Page() {
const headersObj = await headers();
let appSettings: FirebaseServerAppSettings = {};
appSettings.releaseOnDeref = headersObj;
const serverApp = initializeServerApp(firebaseConfig, appSettings);
...
}
Reprendre les sessions authentifiées créées sur le client
Lorsqu'une instance de FirebaseServerApp est initialisée avec un jeton d'ID d'authentification, elle permet de relier les sessions utilisateur authentifiées entre les environnements de rendu côté client (CSR) et de rendu côté serveur (SSR). Les instances du SDK Firebase Auth initialisées avec un objet FirebaseServerApp contenant un jeton d'ID d'authentification tenteront de connecter l'utilisateur lors de l'initialisation sans que l'application n'ait besoin d'appeler des méthodes de connexion.
En fournissant un jeton d'ID Auth, les applications peuvent utiliser n'importe quelle méthode de connexion d'Auth sur le client, ce qui garantit que la session se poursuit côté serveur, même pour les méthodes de connexion qui nécessitent une interaction de l'utilisateur. De plus, il permet de décharger les opérations intensives vers le serveur, telles que les requêtes Firestore authentifiées, ce qui devrait améliorer les performances de rendu de votre application.
/// Next.js
import { initializeServerApp } from "firebase/app";
import { getAuth } from "firebase/auth";
// Replace the following with your app's
// Firebase project configuration
const firebaseConfig = {
// ...
};
const firebaseServerAppSettings = {
authIdToken: token // See "Pass client tokens to the server side
// rendering phase" for an example on how transmit
// the token from the client and the server.
}
const serverApp =
initializeServerApp(firebaseConfig,
firebaseServerAppSettings);
const serverAuth = getAuth(serverApp);
// FirebaseServerApp and Auth will now attempt
// to sign in the current user based on provided
// authIdToken.
Utiliser App Check dans les environnements SSR
L'application d'App Check repose sur une instance du SDK App Check que les SDK Firebase utilisent pour appeler getToken en interne. Le jeton obtenu est ensuite inclus dans les requêtes adressées à tous les services Firebase, ce qui permet au backend de valider l'application.
Toutefois, comme le SDK App Check a besoin d'un navigateur pour accéder à des heuristiques spécifiques pour la validation de l'application, il ne peut pas être initialisé dans des environnements de serveur.
FirebaseServerApp offre une alternative. Si un jeton App Check généré par le client est fourni lors de l'initialisation de FirebaseServerApp, il sera utilisé par les SDK des produits Firebase lors de l'appel des services Firebase, ce qui élimine le besoin d'une instance du SDK App Check.
/// Next.js
import { initializeServerApp } from "firebase/app";
// Replace the following with your app's
// Firebase project configuration
const firebaseConfig = {
// ...
};
const firebaseServerAppSettings = {
appCheckToken: token // See "Pass client tokens to the server side
// rendering phase" for an example on how transmit
// the token from the client and the server.
}
const serverApp =
initializeServerApp(firebaseConfig,
firebaseServerAppSettings);
// The App Check token will now be appended to all Firebase service requests.
Transmettre les jetons client à la phase d'affichage côté serveur
Pour transmettre des jetons d'ID d'authentification (et des jetons App Check) authentifiés du client à la phase de rendu côté serveur (SSR), utilisez un service worker. Cette approche consiste à intercepter les requêtes de récupération qui déclenchent le SSR et à ajouter les jetons aux en-têtes de requête.
Consultez Gestion des sessions avec des service workers pour obtenir une implémentation de référence d'un service worker Firebase Auth. Consultez également la section Modifications côté serveur pour obtenir un code qui montre comment analyser ces jetons à partir des en-têtes afin de les utiliser dans l'initialisation de FirebaseServerApp.
Utiliser Firestore dans des environnements SSR
Lorsque vous créez des applications Web avec le rendu côté serveur (SSR), vous devez souvent partager des données entre le serveur et le client pour optimiser les performances et l'expérience utilisateur. Le SDK Firestore fournit des outils de sérialisation qui vous permettent de capturer des instantanés et des types de données spécifiques sur le serveur, puis de les transmettre directement à vos composants côté client. Ce processus élimine les récupérations redondantes en permettant au client d'hydrater l'état à l'aide des données préchargées pendant la phase SSR. De plus, vous pouvez passer de ces états sérialisés à des écouteurs en temps réel, ce qui garantit que votre application reste synchronisée avec la base de données.
Cette section explique comment réutiliser les données récupérées lors de la phase de rendu côté serveur (SSR) dans les composants côté client.
Sérialiser les types de données
Certains types de données Firestore fournissent une méthode toJSON pour convertir leurs données dans un format sérialisable. Il s'agit d'instances d'objets tels que Bytes, GeoPoint, Timestamp et VectorValue.
Une fois que vous disposez des données au format JSON, vous pouvez les transmettre du serveur au client via des mécanismes de framework standards ou en tant que paramètres aux composants qui couvrent la division. Exemple :
import {
Bytes
} from 'firebase/firestore';
const BYTES_DATA = new Uint8Array([0, 1, 2, 3, 4, 5]);
const bytes = Bytes.fromUint8Array(BYTES_DATA);
const bytesJSON = bytes.toJSON();
Désérialiser les types de données
Les types de données Firestore incluent la méthode statique fromJSON pour convertir les données sérialisées en un type de données Firestore exploitable.
Par exemple, l'instruction suivante désérialise un type de données Bytes :
import {
Bytes
} from 'firebase/firestore';
// Assuming the same `bytesJSON` variable from the previous example.
const deserializedBytes = Bytes.fromJSON(bytesJSON);
Sérialiser et désérialiser des instantanés Firestore
Comme pour les types de données Firestore, vous pouvez sérialiser des instances de DocumentSnapshot et QuerySnapshot à l'aide de toJSON. Toutefois, pour les désérialiser, vous devez utiliser les fonctions autonomes documentSnapshotFromJSON et querySnapshotFromJSON au lieu d'une méthode fromJSON statique.
Par exemple, les résultats querySnapshot d'une opération query peuvent être sérialisés à l'aide de la méthode toJSON :
import {
collection,
getDocs,
query,
querySnapshotFromJSON
} from 'firebase/firestore';
// Assuming a configured instance of Firestore in the variable `firestore`.
const queryRef = query(collection(firestore, QUERY_PATH));
const querySnapshot = await getDocs(queryRef);
const querySnapshotJson = querySnapshot.toJSON();
Ces données peuvent ensuite être désérialisées :
import {
querySnapshotFromJSON
} from 'firebase/firestore';
// deserializedSnapshot is an object of type QuerySnapshot:
const deserializedSnapshot =
querySnapshotFromJSON(firestore, querySnapshotJson);
Écouteurs avec instantanés sérialisés
Bien que les données interrogées pendant la phase SSR soient utiles pour votre rendu CSR initial, vous devrez peut-être toujours surveiller le service Firestore pour obtenir des mises à jour en temps réel de ces informations.
Si votre application nécessite ces mises à jour en temps réel, vous pouvez utiliser la fonction onSnapshotResume pour initialiser les SnapshotListener Firestore avec des données Snapshot sérialisées. Exemple :
const observer = {
next: (qs) => {
console.log("onSnapshot invoked: ", qs.data());
},
error: (e) => {
console.log("error callback invoked: ", e.toString());
}
};
const unsubscribe = onSnapshotResume(firestore, querySnapshotJson, observer);