Quita el código que no se use

En este codelab, quita las dependencias innecesarias y sin usar para mejorar el rendimiento de la siguiente aplicación.

Captura de pantalla de la aplicación

Medir

Siempre es una buena idea medir primero el rendimiento de un sitio web antes de agregar optimizaciones.

  • Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona Pantalla completa pantalla completa.

Haz clic en tu gato favorito. En esta aplicación, se usa Realtime Database de Firebase, por lo que la puntuación se actualiza en tiempo real y se sincroniza con todas las demás personas que usan la aplicación. 🐈

  1. Presiona "Control + Mayús + J" (o bien "Comando + Opción + J" en Mac) para abrir Herramientas para desarrolladores.
  2. Haga clic en la pestaña Red.
  3. Selecciona la casilla de verificación Inhabilitar caché.
  4. Vuelve a cargar la app.

El tamaño original del paquete es de 992 KB.

Se entrega casi 1 MB de JavaScript para cargar esta sencilla aplicación.

Observa las advertencias del proyecto en Herramientas para desarrolladores.

  • Haz clic en la pestaña Consola.
  • Asegúrate de que Warnings esté habilitado en el menú desplegable de niveles junto a la entrada Filter.

Filtro de advertencias

  • Observa la advertencia que se muestra.

Advertencia de la consola

Firebase, que es una de las bibliotecas que se usan en esta aplicación, es un buen samaritano, ya que proporciona una advertencia para que los desarrolladores sepan que no deben importar su paquete completo, sino solo los componentes que se usan. En otras palabras, hay bibliotecas no utilizadas que se pueden quitar en esta aplicación para que se cargue más rápido.

También hay instancias en las que se usa una biblioteca en particular, pero en las que puede haber una alternativa más simple. El concepto de quitar bibliotecas innecesarias se explora más adelante en este instructivo.

Analizando el paquete

Hay dos dependencias principales en la aplicación:

  • Firebase: Es una plataforma que proporciona varios servicios útiles para aplicaciones web, de iOS o de Android. Aquí, su Realtime Database se usa para almacenar y sincronizar la información de cada gatito en tiempo real.
  • Moment.js: Es una biblioteca de utilidades que facilita el control de fechas en JavaScript. La fecha de nacimiento de cada gatito se almacena en la base de datos de Firebase y moment se usa para calcular su edad en semanas.

¿Cómo pueden contribuir solo dos dependencias a un tamaño de paquete de casi 1 MB? Bueno, una de las razones es que cualquier dependencia, a su vez, puede tener sus propias dependencias, por lo que hay mucho más de dos si se considera cada profundidad o rama del "árbol" de dependencia. Es fácil que una aplicación se vuelva grande bastante rápido si se incluyen muchas dependencias.

Analiza el agrupador para tener una mejor idea de lo que sucede. Existen varias herramientas diferentes compiladas por la comunidad que pueden ayudarte a hacerlo, como webpack-bundle-analyzer.

El paquete de esta herramienta ya se incluye en la app como un devDependency.

"devDependencies": {
  //...
  "webpack-bundle-analyzer": "^2.13.1"
},

Esto significa que se puede usar directamente en el archivo de configuración del paquete web. Impórtalo al comienzo de webpack.config.js:

const path = require("path");

//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;

Ahora agrégalo como un complemento al final del archivo dentro del array plugins:

module.exports = {
  //...
  plugins: [
    //...
    new BundleAnalyzerPlugin()
  ]
};

Cuando se vuelva a cargar la aplicación, deberías ver una visualización de todo el paquete, en lugar de la app en sí.

Analizador de paquetes de Webpack

No es tan tierno como ver unos gatitos Hint, pero, de todas maneras, es increíblemente útil. Si colocas el cursor sobre cualquiera de los paquetes, se muestra su tamaño representado de tres maneras diferentes:

Tamaño de las estadísticas Es el tamaño antes de cualquier reducción o compresión.
Tamaño analizado Tamaño del paquete real dentro del paquete después de que se compiló. La versión 4 de webpack (que se usa en esta aplicación) reduce los archivos compilados automáticamente, por lo que es más pequeño que el tamaño de las estadísticas.
Tamaño en formato gzip Tamaño del paquete después de que se comprime con la codificación gzip. Este tema se trata en una guía aparte.

Con la herramienta webpack-bundle-analyzer, es más fácil identificar paquetes sin usar o innecesarios que conforman un gran porcentaje del paquete.

Cómo quitar paquetes sin usar

La visualización muestra que el paquete firebase consta de mucho más que una base de datos. Incluye paquetes adicionales como los siguientes:

  • firestore
  • auth
  • storage
  • messaging
  • functions

Todos estos son servicios increíbles que proporciona Firebase (y consulta la documentación para obtener más información), pero ninguno de ellos se usa en la aplicación, por lo que no es necesario importarlos todos.

Revierte los cambios en webpack.config.js para volver a ver la aplicación:

  • Quita BundleAnalyzerPlugin de la lista de complementos:
plugins: [
  //...
  new BundleAnalyzerPlugin()
];
  • Ahora, quita la importación sin usar de la parte superior del archivo:
const path = require("path");

//...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

Ahora, la aplicación debería cargarse con normalidad. Modifica src/index.js para actualizar las importaciones de Firebase.

import firebase from 'firebase';
import firebase from 'firebase/app';
import 'firebase/database';

Ahora, cuando se vuelva a cargar la app, no se mostrará la advertencia de Herramientas para desarrolladores. Cuando abres el panel Network de Herramientas de desarrollo, también se muestra una reducción buena en el tamaño del paquete:

Se redujo el tamaño del paquete a 480 KB

Se quitó más de la mitad del tamaño del paquete. Firebase proporciona muchos servicios diferentes y les da a los desarrolladores la opción de incluir solo los que sean realmente necesarios. En esta aplicación, solo se usó firebase/database para almacenar y sincronizar todos los datos. La importación de firebase/app, que configura la plataforma de la API para cada uno de los diferentes servicios, siempre es necesaria.

Muchas otras bibliotecas populares, como lodash, también permiten a los desarrolladores importar diferentes partes de sus paquetes de manera selectiva. Sin hacer mucho trabajo, actualizar las importaciones de la biblioteca en una aplicación para que solo incluya lo que se usa puede generar mejoras significativas en el rendimiento.

Aunque el tamaño del paquete se redujo bastante, aún queda trabajo por hacer. 😈

Cómo quitar paquetes innecesarios

A diferencia de Firebase, importar partes de la biblioteca moment no es tan fácil, pero ¿puede quitarse por completo?

El cumpleaños de cada gatito lindo se almacena en formato Unix (milisegundos) en la base de datos de Firebase.

Fechas de nacimiento almacenadas en formato Unix

Esta es una marca de tiempo de una fecha y hora particulares, representada por la cantidad de milisegundos transcurridos desde el 1 de enero de 1970 a las 00:00 UTC. Si la fecha y la hora actuales se pueden calcular en el mismo formato, es probable que se pueda crear una pequeña función para encontrar la edad de cada gatito en semanas.

Como siempre, intenta no copiar y pegar mientras sigues aquí. Primero, quita moment de las importaciones en src/index.js.

import firebase from 'firebase/app';
import 'firebase/database';
import * as moment from 'moment';

Hay un objeto de escucha de eventos de Firebase que controla los cambios de valor en nuestra base de datos:

favoritesRef.on("value", (snapshot) => { ... })

Arriba de esto, agrega una función pequeña para calcular la cantidad de semanas desde una fecha dada:

const ageInWeeks = birthDate => {
  const WEEK_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 7;
  const diff = Math.abs((new Date).getTime() - birthDate);
  return Math.floor(diff / WEEK_IN_MILLISECONDS);
}

En esta función, la diferencia en milisegundos entre la fecha y hora actuales (new Date).getTime() y la fecha de nacimiento (el argumento birthDate, ya en milisegundos) se calcula y divide por la cantidad de milisegundos en una sola semana.

Por último, todas las instancias de moment se pueden quitar en el objeto de escucha de eventos. Para ello, se puede aprovechar esta función:

favoritesRef.on("value", (snapshot) => {
  const { kitties, favorites, names, birthDates } = snapshot.val();
  favoritesScores = favorites;

  kittiesList.innerHTML = kitties.map((kittiePic, index) => {
    const birthday = moment(birthDates[index]);

    return `
      <li>
        <img src=${kittiePic} onclick="favKittie(${index})">
        <div class="extra">
          <div class="details">
            <p class="name">${names[index]}</p>
            <p class="age">${moment().diff(birthday, 'weeks')} weeks old</p>
            <p class="age">${ageInWeeks(birthDates[index])} weeks old</p>
          </div>
          <p class="score">${favorites[index]} ❤</p>
        </div>
      </li>
    `})
});

Ahora vuelve a cargar la aplicación y observa el panel Red una vez más.

Se redujo el tamaño del paquete a 225 KB

¡El tamaño de nuestro paquete se redujo a más de la mitad otra vez!

Conclusión

Con este codelab, comprenderás bien cómo analizar un paquete en particular y por qué puede ser tan útil quitar paquetes sin usar o innecesarios. Antes de comenzar a optimizar una aplicación con esta técnica, es importante que sepas que esto puede ser mucho más complejo en aplicaciones más grandes.

Con respecto a quitar bibliotecas sin utilizar, intenta averiguar qué partes de un paquete se usan y cuáles no. Para ver un paquete de aspecto misterioso que parece no estar en uso en ningún lugar, da un paso atrás y verifica qué dependencias de nivel superior podrían necesitarlo. Intenta encontrar la manera de separarlos.

Cuando se trata de quitar bibliotecas innecesarias, el proceso puede ser un poco más complicado. Es importante trabajar en estrecha colaboración con tu equipo y ver si hay potencial para simplificar partes de la base de código. Puede parecer que quitar moment de esta aplicación es lo correcto siempre, pero ¿qué pasaría si se deben procesar zonas horarias y diferentes configuraciones regionales? ¿O si hubiera manipulaciones de fechas más complicadas? El proceso puede ser muy complejo cuando se manipulan y analizan fechas y horas, y las bibliotecas como moment y date-fns simplifican esta tarea de manera significativa.

Todo representa una compensación, y es importante evaluar si vale la pena la complejidad y el esfuerzo de implementar una solución personalizada en lugar de depender de una biblioteca de terceros.