Passer de l'API avec espace de noms à l'application modulaire

Les applications qui utilisent une API Web Firebase avec un espace de noms, à partir des bibliothèques compat jusqu'à la version 8 ou antérieure, doivent envisager de migrer vers l'API modulaire en suivant les instructions de ce guide.

Ce guide part du principe que vous connaissez l'API avec espace de noms et que vous allez utiliser un bundler de module tel que webpack ou Rollup pour la mise à niveau et le développement continu d'applications modulaires.

Il est fortement recommandé d'utiliser un bundler de modules dans votre environnement de développement. Si vous n'en utilisez pas, vous ne pourrez pas profiter des principaux avantages de l'API modulaire en termes de réduction de la taille de l'application. Vous aurez besoin de npm ou de yarn pour installer le SDK.

Les étapes de mise à niveau de ce guide seront basées sur une application Web imaginaire qui utilise les SDK Authentication et Cloud Firestore. En étudiant les exemples, vous pourrez maîtriser les concepts et les étapes pratiques nécessaires pour mettre à niveau tous les SDK Web Firebase compatibles.

À propos des bibliothèques avec espace de noms (compat)

Deux types de bibliothèques sont disponibles pour le SDK Web Firebase :

  • Modulaire : une nouvelle surface d'API conçue pour faciliter l'élimination du code inutilisé (tree-shaking) afin de rendre votre application Web aussi petite et rapide que possible.
  • Avec espace de noms (compat) : une surface d'API familière entièrement compatible avec les versions antérieures du SDK, qui vous permet de mettre à niveau sans modifier tout votre code Firebase en même temps. Les bibliothèques de compatibilité n'offrent que peu, voire aucun avantage en termes de taille ou de performances par rapport à leurs homologues avec espace de noms.

Ce guide part du principe que vous allez tirer parti des bibliothèques de compatibilité pour faciliter votre mise à niveau. Ces bibliothèques vous permettent de continuer à utiliser du code avec espace de noms en parallèle du code refactorisé pour l'API modulaire. Cela signifie que vous pouvez compiler et déboguer votre application plus facilement tout au long du processus de mise à niveau.

Pour les applications très peu exposées au SDK Web Firebase (par exemple, une application qui n'effectue qu'un simple appel aux API Authentication), il peut être pratique de refactoriser l'ancien code avec espace de noms sans utiliser les bibliothèques de compatibilité. Si vous mettez à niveau une telle application, vous pouvez suivre les instructions de ce guide pour "l'API modulaire" sans utiliser les bibliothèques de compatibilité.

À propos de la procédure de mise à niveau

Chaque étape du processus de mise à niveau est limitée afin que vous puissiez terminer de modifier la source de votre application, puis la compiler et l'exécuter sans problème. En résumé, voici ce que vous devez faire pour mettre à niveau une application :

  1. Ajoutez les bibliothèques modulaires et les bibliothèques de compatibilité à votre application.
  2. Mettez à jour les instructions d'importation dans votre code pour qu'elles soient compatibles.
  3. Refactorisez le code pour un seul produit (par exemple, Authentication) au style modulaire.
  4. Facultatif : À ce stade, supprimez la bibliothèque de compatibilité Authentication et le code de compatibilité pour Authentication afin de bénéficier de la réduction de la taille de l'application pour Authentication avant de continuer.
  5. Refactorisez les fonctions pour chaque produit (par exemple, Cloud Firestore, FCM, etc.) au style modulaire, en compilant et en testant jusqu'à ce que toutes les zones soient terminées.
  6. Mettez à jour le code d'initialisation pour qu'il adopte le style modulaire.
  7. Supprimez toutes les instructions et le code de compatibilité restants de votre application.

Obtenir la dernière version du SDK

Pour commencer, obtenez les bibliothèques modulaires et les bibliothèques de compatibilité à l'aide de npm :

npm i firebase@12.0.0

# OR

yarn add firebase@12.0.0

Mettre à jour les importations pour la compatibilité

Pour que votre code continue de fonctionner après la mise à jour de vos dépendances, modifiez vos instructions d'importation afin d'utiliser la version "compat" de chaque importation. Exemple :

Avant : version 8 ou antérieure

import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

Après : compat

// compat packages are API compatible with namespaced code
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';

Refactoriser vers le style modulaire

Alors que les API avec espace de noms sont basées sur un modèle d'espace de noms et de service enchaîné par des points, l'approche modulaire signifie que votre code sera principalement organisé autour des fonctions. Dans l'API modulaire, le package firebase/app et d'autres packages ne renvoient pas d'exportation complète contenant toutes les méthodes du package. Au lieu de cela, les packages exportent des fonctions individuelles.

Dans l'API modulaire, les services sont transmis en tant que premier argument, et la fonction utilise ensuite les détails du service pour faire le reste. Examinons comment cela fonctionne dans deux exemples qui refactorisent les appels aux API Authentication et Cloud Firestore.

Exemple 1 : Refactoriser une fonction Authentication

Avant : compat

Le code de compatibilité est identique au code avec espace de noms, mais les importations ont changé.

import firebase from "firebase/compat/app";
import "firebase/compat/auth";

const auth = firebase.auth();
auth.onAuthStateChanged(user => { 
  // Check for user status
});

Après : modulaire

La fonction getAuth utilise firebaseApp comme premier paramètre. La fonction onAuthStateChanged n'est pas enchaînée à partir de l'instance auth comme elle le serait dans l'API avec espace de noms. Au lieu de cela, il s'agit d'une fonction libre qui prend auth comme premier paramètre.

import { getAuth, onAuthStateChanged } from "firebase/auth";

const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => {
  // Check for user status
});

Mise à jour de la gestion de la méthode d'authentification getRedirectResult

L'API modulaire introduit une modification destructive dans getRedirectResult. Lorsqu'aucune opération de redirection n'est appelée, l'API modulaire renvoie null, contrairement à l'API avec espace de noms, qui renvoyait un UserCredential avec un utilisateur null.

Avant : compat

const result = await auth.getRedirectResult()
if (result.user === null && result.credential === null) {
  return null;
}
return result;

Après : modulaire

const result = await getRedirectResult(auth);
// Provider of the access token could be Facebook, Github, etc.
if (result === null || provider.credentialFromResult(result) === null) {
  return null;
}
return result;

Exemple 2 : Refactoriser une fonction Cloud Firestore

Avant : compat

import "firebase/compat/firestore"

const db = firebase.firestore();
db.collection("cities").where("capital", "==", true)
    .get()
    .then((querySnapshot) => {
        querySnapshot.forEach((doc) => {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
    })
    .catch((error) => {
        console.log("Error getting documents: ", error);
    });

Après : modulaire

La fonction getFirestore utilise firebaseApp comme premier paramètre, qui a été renvoyé par initializeApp dans un exemple précédent. Notez que le code permettant de former une requête est très différent dans l'API modulaire. Il n'y a pas d'enchaînement, et les méthodes telles que query ou where sont désormais exposées en tant que fonctions libres.

import { getFirestore, collection, query, where, getDocs } from "firebase/firestore";

const db = getFirestore(firebaseApp);

const q = query(collection(db, "cities"), where("capital", "==", true));

const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
  // doc.data() is never undefined for query doc snapshots
  console.log(doc.id, " => ", doc.data());
});

Mise à jour des références à Firestore DocumentSnapshot.exists

L'API modulaire introduit une modification radicale dans laquelle la propriété firestore.DocumentSnapshot.exists a été remplacée par une méthode. La fonctionnalité est essentiellement la même (tester si un document existe), mais vous devez refactoriser votre code pour utiliser la nouvelle méthode, comme indiqué ci-dessous :

Before:compat

if (snapshot.exists) {
  console.log("the document exists");
}

Après : modulaire

if (snapshot.exists()) {
  console.log("the document exists");
}

Exemple 3 : combiner les styles de code avec espaces de noms et modulaires

L'utilisation des bibliothèques de compatibilité lors de la mise à niveau vous permet de continuer à utiliser le code avec espace de noms à côté du code refactorisé pour l'API modulaire. Cela signifie que vous pouvez conserver le code avec espace de noms existant pour Cloud Firestore pendant que vous refactorisez Authentication ou un autre code du SDK Firebase au style modulaire, et compiler quand même votre application avec les deux styles de code. Il en va de même pour le code d'API modulaire et avec espace de noms dans un produit tel que Cloud Firestore. Les anciens et nouveaux styles de code peuvent coexister, à condition que vous importiez les packages de compatibilité :

import firebase from 'firebase/compat/app';
import 'firebase/compat/firestore';
import { getDoc } from 'firebase/firestore'

const docRef = firebase.firestore().doc();
getDoc(docRef);

N'oubliez pas que, même si votre application sera compilée, vous ne bénéficierez pas des avantages de la taille de l'application du code modulaire tant que vous n'aurez pas supprimé complètement les instructions et le code de compatibilité de votre application.

Mettre à jour le code d'initialisation

Mettez à jour le code d'initialisation de votre application pour utiliser la syntaxe modulaire. Il est important de mettre à jour ce code après avoir refactorisé tout le code de votre application. En effet, firebase.initializeApp() initialise l'état global pour les API compatibles et modulaires, tandis que la fonction modulaire initializeApp() n'initialise que l'état pour le modulaire.

Avant : compat

import firebase from "firebase/compat/app"

firebase.initializeApp({ /* config */ });

Après : modulaire

import { initializeApp } from "firebase/app"

const firebaseApp = initializeApp({ /* config */ });

Supprimer le code de compatibilité

Pour profiter des avantages de taille de l'API modulaire, vous devez à terme convertir toutes les invocations au style modulaire présenté ci-dessus et supprimer toutes les instructions import "firebase/compat/* de votre code. Une fois terminé, il ne devrait plus y avoir de références à l'espace de noms global firebase.* ni à aucun autre code dans le style d'API avec espace de noms.

Utiliser la bibliothèque de compatibilité à partir de la fenêtre

L'API modulaire est optimisée pour fonctionner avec des modules plutôt qu'avec l'objet window du navigateur. Les versions précédentes de la bibliothèque permettaient de charger et de gérer Firebase à l'aide de l'espace de noms window.firebase. Cette approche n'est pas recommandée à l'avenir, car elle ne permet pas d'éliminer le code inutilisé. Toutefois, la version compatible du SDK JavaScript fonctionne avec window pour les développeurs qui préfèrent ne pas commencer immédiatement le processus de mise à niveau modulaire.

<script src="https://www.gstatic.com/firebasejs/12.0.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/12.0.0/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/12.0.0/firebase-auth-compat.js"></script>
<script>
   const firebaseApp = firebase.initializeApp({ /* Firebase config */ });
   const db = firebaseApp.firestore();
   const auth = firebaseApp.auth();
</script>

La bibliothèque de compatibilité utilise un code modulaire en interne et le fournit avec la même API que l'API avec espace de noms. Cela signifie que vous pouvez vous référer à la documentation de l'API avec espace de noms et aux extraits de code avec espace de noms pour en savoir plus. Cette méthode n'est pas recommandée pour une utilisation à long terme, mais elle peut servir de point de départ pour passer à la bibliothèque entièrement modulaire.

Avantages et limites du SDK modulaire

Le SDK entièrement modularisé présente les avantages suivants par rapport aux versions précédentes :

  • Le SDK modulaire permet de réduire considérablement la taille de l'application. Il adopte le format de module JavaScript moderne, ce qui permet des pratiques de "tree shaking" dans lesquelles vous n'importez que les artefacts dont votre application a besoin. Selon votre application, l'élimination du code mort avec le SDK modulaire peut entraîner une réduction de 80 % des kilooctets par rapport à une application comparable créée à l'aide de l'API avec espace de noms.
  • Le SDK modulaire continuera de bénéficier du développement continu de fonctionnalités, contrairement à l'API avec espace de noms.