Usa agrupadores de módulos con Firebase

Los agrupadores de módulos de JavaScript pueden hacer muchas tareas, pero una de sus funciones más útiles es la capacidad de agregar y usar bibliotecas externas en la base de código. Los agrupadores de módulos leen las rutas de importación de tu código y combinan (agrupan) el código específico de tu aplicación con el código de tu biblioteca importada.

A partir de la versión 9 y posteriores, la API modular de Firebase JavaScript está optimizada para trabajar con las funciones de optimización de los agrupadores de módulos para reducir la cantidad de código de Firebase incluido en la compilación final.

import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged, getRedirectResult } from 'firebase/auth';

const firebaseApp = initializeApp({ /* config */ });
const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => { /* check status */ });

/**
 * getRedirectResult is unused and should not be included in the code base.
 * In addition, there are many other functions within firebase/auth that are
 * not imported and therefore should not be included as well.
 */

El proceso de eliminación de código no utilizado de una biblioteca se conoce en inglés como “tree shaking”. Sería muy lento y propenso a errores quitar este código de forma manual, pero los agrupadores de módulos pueden automatizar este proceso.

En el ecosistema de JavaScript, hay muchos agrupadores de módulos de alta calidad. Esta guía se enfoca en el uso de Firebase con webpack, Rollup y esbuild.

Primeros pasos

Debes tener instalado npm en tu entorno de desarrollo. Este se usa para instalar y administrar dependencias (bibliotecas). Para instalar npm, instala Node.js, que incluye npm automáticamente.

La mayoría de los desarrolladores están configurados correctamente una vez que se instala Node.js. Sin embargo, existen problemas comunes que muchos desarrolladores se encuentran cuando configuran su entorno. Si detectas algún error, asegúrate de que tu entorno tenga la CLI de npm y de que estén configurados los permisos adecuados para que no debas instalar paquetes como administrador con el comando sudo.

Genera el archivo package.json e instala Firebase

Una vez que hayas instalado npm, deberás crear un archivo package.json en la raíz de tu proyecto local. Genera este archivo con el siguiente comando npm:

npm init

Se iniciará un asistente que te solicitará la información necesaria. Una vez creado el archivo, será similar al siguiente:

{
  "name": "your-package-name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {

  }
}

Este archivo es responsable de muchos aspectos diferentes. Es fundamental que te familiarices con él si quieres obtener más información sobre la agrupación de módulos y el desarrollo de código JavaScript en general. La pieza importante de esta guía es el objeto "dependencies". Este objeto contendrá un par clave-valor de la biblioteca que tienes instalada y la versión que usa.

Las dependencias se agregan mediante los comandos npm install o npm i.

npm i firebase

Cuando ejecutes npm i firebase, el proceso de instalación actualizará package.json para mostrar Firebase como una dependencia:

  "dependencies": {
    "firebase": "^9.0.0"
  },

La clave es el nombre de la biblioteca y el valor es la versión que se debe usar. El valor de la versión es flexible y puede aceptar un rango de valores. Esto se conoce como control de versiones semántico o semver. Para obtener más información, consulta la guía de npm sobre el control de versiones semántico.

Comparación entre carpetas de origen y compilación

El agrupador de módulos lee y procesa el código que escribes y, luego, lo genera como un archivo nuevo o un conjunto de archivos. Es importante separar estos dos tipos de archivos. El código que leen y procesan los agrupadores de módulos se conoce como código “fuente”. Los archivos que generan se conocen como el código de compilado o “dist” (distribución).

Una configuración común en las bases de código es almacenar el código fuente en una carpeta llamada src y el código compilado en otra carpeta llamada dist.

- src
 |_ index.js
 |_ animations.js
 |_ datalist.js


- dist
 |_ bundle.js

En la estructura de archivos de ejemplo anterior, considera que index.js importa animations.js y datalist.js. Cuando un agrupador de módulos procesa el código fuente, produce el archivo bundle.js en la carpeta dist. El bundle.js es una combinación de los archivos de la carpeta src y de cualquier biblioteca que se importe.

Si usas sistemas de control de fuente como Git, es común pasar por alto la carpeta dist cuando se almacena este código en el repositorio principal.

Puntos de entrada

Los agrupadores de módulos tienen un concepto de punto de entrada. Puedes pensar en la aplicación como un árbol de archivos. Un archivo importa código desde otro, y así sucesivamente. Esto significa que un archivo será la raíz del árbol. Este archivo se conoce como punto de entrada.

Revisemos nuevamente el ejemplo de estructura de archivos anterior.

- src
 |_ index.js
 |_ animations.js
 |_ datalist.js


- dist
 |_ bundle.js
// src/index.js
import { animate } from './animations';
import { createList } from './datalist';

// This is not real code, but for example purposes only
const theList = createList('users/123/tasks');
theList.addEventListener('loaded', event => {
  animate(theList);
});

El archivo src/index.js se considera el punto de entrada porque comienza las importaciones de todo el código necesario para la aplicación. Los agrupadores de módulos usan este archivo de punto de entrada para comenzar el proceso de agrupación.

Usa Firebase con webpack

No se necesita una configuración específica para las apps de Firebase y el paquete web. En esta sección, se aborda una configuración general de webpack.

El primer paso es instalar webpack desde npm como dependencia de desarrollo.

npm i webpack webpack-cli -D

Crea un archivo en la raíz de tu proyecto local llamado webpack.config.js y agrega el siguiente código.

const path = require('path');

module.exports = {
  // The entry point file described above
  entry: './src/index.js',
  // The location of the build folder described above
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  // Optional and for development only. This provides the ability to
  // map the built code back to the original source format when debugging.
  devtool: 'eval-source-map',
};

Luego, asegúrate de tener Firebase instalado como dependencia.

npm i firebase

Luego, inicializa Firebase en tu base de código. El siguiente código importa e inicializa Firebase en un archivo de punto de entrada y usa Firestore Lite para cargar un documento llamado “city”.

// src/index.js
import { initializeApp } from 'firebase/app';
import { getFirestore, doc, getDoc } from 'firebase/firestore/lite';

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

async function loadCity(name) {
  const cityDoc = doc(db, `cities/${name}`);
  const snapshot = await getDoc(cityDoc);
  return {
    id: snapshot.id,
    ...snapshot.data(),
  };
}

El siguiente paso es agregar una secuencia de comandos de npm para ejecutar la compilación del paquete web. Abre el archivo package.json y agrega el siguiente par clave-valor al objeto "scripts".

  "scripts": {
    "build": "webpack --mode=development"
  },

Para ejecutar webpack y generar la carpeta de compilación, ejecute el siguiente comando:

npm run build

Por último, revisa la carpeta de compilación dist. Debe contener un archivo llamado bundle.js que contenga el paquete de aplicación y el código de dependencia.

Consulta la documentación oficial sobre el parámetro de configuración “mode” si necesitas más información a fin de optimizar la compilación de paquetes web para la fase de producción.

Usa Firebase con Rollup

Las apps de Firebase con Rollup no requieren configuración específica. En esta sección, se describe una configuración general de Rollup.

El primer paso es instalar Rollup y un complemento que se usa para asignar importaciones a dependencias instaladas con npm.

npm i rollup @rollup/plugin-node-resolve -D

Crea un archivo en la raíz de tu proyecto local llamado rollup.config.js y agrega el siguiente código.

import { nodeResolve } from '@rollup/plugin-node-resolve';

export default {
  // the entry point file described above
  input: 'src/index.js',
  // the output for the build folder described above
  output: {
    file: 'dist/bundle.js',
    // Optional and for development only. This provides the ability to
    // map the built code back to the original source format when debugging.
    sourcemap: 'inline',
    // Configure Rollup to convert your module code to a scoped function
    // that "immediate invokes". See the Rollup documentation for more
    // information: https://rollupjs.org/guide/en/#outputformat
    format: 'iife'
  },
  // Add the plugin to map import paths to dependencies
  // installed with npm
  plugins: [nodeResolve()]
};

Luego, inicializa Firebase en tu base de código. El siguiente código importa e inicializa Firebase en un archivo de punto de entrada y usa Firestore Lite para cargar un documento llamado “city”.

// src/index.js
import { initializeApp } from 'firebase/app';
import { getFirestore, doc, getDoc } from 'firebase/firestore/lite';

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

async function loadCity(name) {
  const cityDoc = doc(db, `cities/${name}`);
  const snapshot = await getDoc(cityDoc);
  return {
    id: snapshot.id,
    ...snapshot.data(),
  };
}

El siguiente paso es agregar una secuencia de comandos npm para ejecutar la compilación de Rollup. Abre el archivo package.json y agrega el siguiente par clave-valor al objeto "scripts".

  "scripts": {
    "build": "rollup -c rollup.config.js"
  },

Para ejecutar Rollup y generar la carpeta de compilación, ejecuta el siguiente comando.

npm run build

Por último, revisa la carpeta de compilación dist. Debe contener un archivo llamado bundle.js que contenga el paquete de aplicación y el código de dependencia.

Consulta la documentación oficial sobre complementos para compilaciones de producción si necesitas más detalles a fin de optimizar la compilación de Rollup para la fase de producción.

Usa Firebase con esbuild

Las apps de Firebase con esbuild no requieren configuración específica. En esta sección, se describe una configuración general de compilación.

El primer paso es instalar esbuild como dependencia de desarrollo.

npm i esbuild -D

Crea un archivo en la raíz de tu proyecto local llamado esbuild.config.js y agrega el siguiente código.

require('esbuild').build({
  // the entry point file described above
  entryPoints: ['src/index.js'],
  // the build folder location described above
  outfile: 'dist/bundle.js',
  bundle: true,
  // Replace with the browser versions you need to target
  target: ['chrome60', 'firefox60', 'safari11', 'edge20'],
  // Optional and for development only. This provides the ability to
  // map the built code back to the original source format when debugging.
  sourcemap: 'inline',
}).catch(() => process.exit(1))

Luego, inicializa Firebase en tu base de código. El siguiente código importa e inicializa Firebase en un archivo de punto de entrada y usa Firestore Lite para cargar un documento llamado “city”.

// src/index.js
import { initializeApp } from 'firebase/app';
import { getFirestore, doc, getDoc } from 'firebase/firestore/lite';

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

async function loadCity(name) {
  const cityDoc = doc(db, `cities/${name}`);
  const snapshot = await getDoc(cityDoc);
  return {
    id: snapshot.id,
    ...snapshot.data(),
  };
}

El siguiente paso es agregar una secuencia de comandos de npm para ejecutar esbuild. Abre el archivo package.json y agrega el siguiente par clave-valor al objeto "scripts".

  "scripts": {
    "build": "node ./esbuild.config.js"
  },

Por último, revisa la carpeta de compilación dist. Debe contener un archivo llamado bundle.js que posea el paquete de aplicación y el código de dependencia.

Consulta la documentación oficial sobre la reducción y otras optimizaciones si necesitas más información a fin de optimizar esbuild para la fase de producción.