Actualiza de la API con espacio de nombres a la API modular

En el caso de las apps que actualmente usan cualquier API de Firebase Web con espacio de nombres, desde las bibliotecas compat hasta la versión 8 o anteriores, debes considerar migrar las API modulares según las instrucciones de esta guía.

En esta guía, se supone que conoces la API con espacio de nombres y que aprovecharás un agrupador de módulos como webpack o Rollup para actualizar y continuar el desarrollo modular de apps.

Te recomendamos enfáticamente usar un agrupador de módulos en tu entorno de desarrollo. Si no lo usas, no podrás aprovechar los principales beneficios de la API modular en cuanto a la reducción de tamaño de las apps. Necesitarás npm o yarn para instalar el SDK.

Los pasos de actualización de esta guía se basan en una app web imaginaria que usa los SDK de Authentication y de Cloud Firestore. Siguiendo los ejemplos, podrás dominar los conceptos y pasos prácticos necesarios para actualizar todos los SDK web compatibles de Firebase.

Acerca de las bibliotecas con espacio de nombres (compat)

Hay dos tipos de bibliotecas disponibles para el SDK web de Firebase:

  • Modulares: Son nuevas plataformas de API diseñadas para facilitar la eliminación de código no utilizado para que tu app web sea lo más pequeña y rápida posible.
  • Con espacio de nombres (compat): Son plataformas de API conocidas que tienen compatibilidad total con las versiones anteriores del SDK, lo que te permite actualizar sin cambiar todo el código de Firebase de una sola vez. Las bibliotecas de compatibilidad tienen ventajas mínimas o nulas de tamaño o rendimiento en comparación con sus contrapartes con espacio de nombres.

En esta guía, se supone que aprovecharás las bibliotecas de compatibilidad para facilitar la actualización. Estas bibliotecas te permiten seguir usando código con espacio de nombres junto con el código refactorizado para la API modular. Es decir, puedes compilar y depurar tu app con mayor facilidad durante el proceso de actualización.

En el caso de las apps que tienen una exposición muy pequeña al SDK web de Firebase (por ejemplo, una app que realiza solo una llamada simple a las APIs de Authentication), puede ser práctico refactorizar el código con espacio de nombres más antiguo sin usar las bibliotecas de compatibilidad. Si actualizas una app de este tipo, puedes seguir las instrucciones de “la API modular” de esta guía sin usar las bibliotecas de compatibilidad.

Acerca del proceso de actualización

Cada paso del proceso de actualización está delimitado de manera que puedas terminar de editar el código fuente de tu app y, luego, compilarla y ejecutarla sin fallas. En resumen, la actualización de una app consta de estos pasos:

  1. Agrega las bibliotecas modulares y las bibliotecas de compatibilidad a tu app.
  2. Actualiza las sentencias de importación del código al formato de compatibilidad.
  3. Refactoriza el código de un solo producto (por ejemplo, Authentication) con el estilo modular.
  4. Opcional: En este punto, quita la biblioteca y el código compatibles de Authentication para obtener el beneficio de tamaño de la app de Authentication antes de continuar.
  5. Refactoriza las funciones de cada producto (por ejemplo, Cloud Firestore, FCM, etc.) con el estilo modular. Compila y prueba el código hasta completar todas las áreas.
  6. Actualiza el código de inicialización con el estilo modular.
  7. Quita todas las sentencias y el código de compatibilidad de tu app.

Obtén la versión más reciente del SDK

Para comenzar, obtén las bibliotecas modulares y las bibliotecas de compatibilidad con npm:

npm i firebase@10.4.0

# OR

yarn add firebase@10.4.0

Actualiza las importaciones al formato de compatibilidad

Para que tu código siga funcionando después de actualizar las dependencias, cambia las sentencias de importación para que usen la versión de “compatibilidad” de cada importación. Por ejemplo:

Antes: Versión 8 o anterior

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

Después: formato de compatibilidad

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

Refactoriza con el estilo modular

Si bien las APIs con espacio de nombres se basan en un espacio de nombres y un patrón de servicio de cadena de puntos, el enfoque modular significa que el código se organizará principalmente en torno a las funciones. En la API modular, el paquete firebase/app y los demás no muestran una exportación completa que contiene todos los métodos del paquete. En cambio, los paquetes exportan funciones individuales.

En la API modular, los servicios se pasan como el primer argumento y, luego, la función usa los detalles del servicio para hacer el resto. Examinemos cómo funciona este enfoque en dos ejemplos que refactorizan las llamadas a las APIs de Authentication y de Cloud Firestore.

Ejemplo 1: Refactoriza una función de Authentication

Antes: Formato de compatibilidad

El código de compatibilidad es idéntico al código con espacio de nombres, pero las importaciones cambiaron.

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

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

Después: Modular

La función getAuth acepta firebaseApp como primer parámetro. La función onAuthStateChanged no está encadenada desde la instancia de auth como lo estaría en la API con espacio de nombres. En cambio, es una función libre que acepta auth como primer parámetro.

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

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

Actualiza el manejo del método Auth getRedirectResult

La API modular presenta un cambio rotundo en getRedirectResult. Cuando no se llama a una operación de redireccionamiento, la API modular muestra null, a diferencia de la API con espacio de nombres, que muestra un UserCredential con un usuario null.

Antes: Formato de compatibilidad

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

Después: Modular

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;

Ejemplo 2: Refactoriza una función de Cloud Firestore

Antes: Formato de compatibilidad

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);
    });

Después: Modular

La función getFirestore acepta firebaseApp como primer parámetro, que se mostró desde initializeApp en un ejemplo anterior. Ten en cuenta que el código para formar una consulta es muy diferente en la API modular: no hay encadenamiento, y los métodos como query o where ahora se exponen como funciones 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());
});

Actualiza las referencias a Firestore DocumentSnapshot.exists

La API modular presenta un cambio rotundo: la propiedad firestore.DocumentSnapshot.exists se convirtió en un método. La funcionalidad es básicamente la misma (probar si existe un documento), pero debes refactorizar tu código para usar el método de la versión más reciente como se muestra a continuación:

Antes: Formato compatible

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

Después: Modular

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

Ejemplo 3: Combina estilos de código modulares y con espacio de nombres

El uso de las bibliotecas de compatibilidad durante la actualización te permite seguir usando código con espacio de nombres junto con el código refactorizado para la API modular. Esto significa que puedes conservar el código con espacio de nombres existente para Cloud Firestore mientras refactorizas Authentication o cualquier otro código del SDK de Firebase con el estilo modular y, de todos modos, compilar correctamente tu app con ambos estilos de código. Lo mismo sucede con el código de la API modular y con espacio de nombres de un producto como Cloud Firestore. Los estilos de código nuevo y antiguo pueden coexistir, siempre que importes los paquetes de compatibilidad:

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

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

Ten en cuenta que, si bien se compilará la app, no obtendrás los beneficios de tamaño de la app que brinda el código modular hasta que quites de ella todas las sentencias y el código de compatibilidad.

Actualiza el código de inicialización

Actualiza el código de inicialización de tu app para usar la sintaxis modular. Es importante que lo hagas después de completar la refactorización de todo el código de la app, ya que firebase.initializeApp() inicializa el estado global de las APIs modulares y las compatibles, mientras que la función modular initializeApp() inicializa solo el estado de las APIs modulares.

Antes: Formato de compatibilidad

import firebase from "firebase/compat/app"

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

Después: Modular

import { initializeApp } from "firebase/app"

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

Quita el código de compatibilidad

Si quieres obtener los beneficios de tamaño que brinda la API modular, en algún momento, debes convertir todas las invocaciones al estilo modular que se indicó anteriormente y quitar todas las sentencias import "firebase/compat/* de tu código. Cuando termines, no debería haber más referencias al espacio de nombres global firebase.* ni ningún otro código con el estilo de API con espacios de nombres.

Usa la biblioteca de compatibilidad desde la ventana

La API modular está optimizada para funcionar con módulos en lugar de con el objeto window del navegador. Las versiones anteriores de la biblioteca permitían la carga y la administración de Firebase con el espacio de nombres window.firebase. Esto no se recomienda de ahora en adelante, ya que no permite la eliminación de código no utilizado. Sin embargo, la versión de compatibilidad del SDK de JavaScript funciona con window para los desarrolladores que prefieren no comenzar de inmediato la ruta de actualización modular.

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

La biblioteca de compatibilidad usa código modular de forma interna y te proporciona la misma API que la API con espacio de nombres. Esto significa que puedes consultar la referencia de la API con espacio de nombres y los fragmentos de código con espacio de nombres para obtener más detalles. Este método no se recomienda para uso a largo plazo, pero sí como inicio de la actualización a la biblioteca completamente modular.

Beneficios y limitaciones del SDK modular

El SDK completamente modular tiene las siguientes ventajas en comparación con las versiones anteriores:

  • El SDK modular permite una reducción drástica del tamaño de la app. Adopta el formato moderno de módulos de JavaScript, lo que permite las prácticas de eliminación de código no utilizado, en las que importas solo los artefactos que necesita tu app. Según la app, la eliminación de código no utilizado con el SDK modular puede reducir hasta en un 80% el tamaño de kilobytes de una app comparable compilada con la API con espacios de nombres.
  • El SDK modular seguirá beneficiándose del desarrollo continuo de funciones, mientras que la API con espacio de nombres no.