Quita el código que no se use

En este codelab, mejorarás el rendimiento de la siguiente aplicación quitando las dependencias que no se usan y que no son necesarias.

Captura de pantalla de la app

Medir

Siempre es buena idea medir primero el rendimiento de un sitio web antes de añadir optimizaciones.

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

Adelante, haz clic en tu gatito 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úsculas + J" (o "Comando + Opción + J" en Mac) para abrir DevTools.
  2. Haga clic en la pestaña Red.
  3. Selecciona la casilla de verificación Inhabilitar caché.
  4. Vuelve a cargar la app.

Tamaño del paquete original de 992 KB

Se envía casi 1 MB de JavaScript para cargar esta aplicación simple.

Consulta las advertencias del proyecto en DevTools.

  • 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

  • Consulta 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 informar a los desarrolladores que no deben importar todo el paquete, sino solo los componentes que se usan. En otras palabras, hay bibliotecas que no se usan y que se pueden quitar de esta aplicación para que se cargue más rápido.

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

Cómo analizar el paquete

Hay dos dependencias principales en la aplicación:

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

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

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

El paquete de esta herramienta ya está incluido 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 de webpack. Importarlo al principio de webpack.config.js:

const path = require("path");

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

Ahora, agrégalo como 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 del paquete completo en lugar de la app.

Webpack Bundle Analyzer

No es tan lindo como ver gatitos 🐱, pero es muy útil. Si colocas el cursor sobre cualquiera de los paquetes, se mostrará su tamaño representado de tres maneras diferentes:

Tamaño de la estadística Es el tamaño antes de cualquier reducción o compresión.
Tamaño analizado Es el tamaño del paquete real dentro del paquete después de que se compila. 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 comprimido con gzip Es el tamaño del paquete después de que se comprime con codificación gzip. Este tema se explica en una guía aparte.

Con la herramienta webpack-bundle-analyzer, es más fácil identificar los paquetes que no se usan o que no son necesarios y que conforman un gran porcentaje del paquete.

Cómo quitar paquetes que no se usan

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

  • firestore
  • auth
  • storage
  • messaging
  • functions

Estos son servicios increíbles que proporciona Firebase (consulta la documentación para obtener más información), pero ninguno de ellos se usa en la aplicación, por lo que no hay ningún motivo para 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;

La aplicación debería cargarse normalmente. 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 vuelve a cargar la app, no se muestra la advertencia de DevTools. Si abres el panel Network de DevTools, también verás una buena reducción en el tamaño del paquete:

El tamaño del paquete se redujo a 480 KB.

Se quitó más de la mitad del tamaño del paquete. Firebase proporciona muchos servicios diferentes y les brinda a los desarrolladores la opción de incluir solo los que realmente son 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 obligatoria.

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

Aunque el tamaño del paquete se redujo bastante, aún hay más trabajo por hacer. 😈

Cómo quitar paquetes innecesarios

A diferencia de Firebase, no se puede importar parte de la biblioteca moment con la misma facilidad, pero quizás se pueda quitar por completo.

El cumpleaños de cada gatito 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 en particular 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 construir una pequeña función para encontrar la edad de cada gatito en semanas.

Como siempre, intenta no copiar y pegar mientras sigues estos pasos. Comienza por quitar 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 pequeña función para calcular la cantidad de semanas a partir de una fecha determinada:

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, se calcula la diferencia en milisegundos entre la fecha y la hora actuales (new Date).getTime() y la fecha de nacimiento (el argumento birthDate, ya en milisegundos) y se divide por la cantidad de milisegundos en una sola semana.

Por último, todas las instancias de moment se pueden quitar del objeto de escucha de eventos si se aprovecha 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.

El tamaño del paquete se redujo a 225 KB.

El tamaño de nuestro paquete se redujo más de la mitad.

Conclusión

Con este codelab, deberías tener una buena comprensión de cómo analizar un paquete en particular y por qué puede ser tan útil quitar paquetes que no se usan o no son necesarios. Antes de comenzar a optimizar una aplicación con esta técnica, es importante saber que esto puede ser mucho más complejo en aplicaciones más grandes.

En lo que respecta a la eliminación de bibliotecas sin usar, intenta averiguar qué partes de un paquete se usan y cuáles no. Si ves un paquete con un aspecto misterioso que parece no estar en uso en ningún lugar, haz un paso atrás y verifica qué dependencias de nivel superior podrían necesitarlo. Intenta encontrar una forma de desvincularlos.

Cuando se trata de quitar bibliotecas innecesarias, las cosas pueden ser un poco más complicadas. Es importante trabajar en estrecha colaboración con tu equipo y ver si hay potencial para simplificar partes de la base de código. Quitar moment en esta aplicación puede parecer lo correcto de hacer cada vez, pero ¿qué sucede si hay zonas horarias y configuraciones regionales diferentes que se deben controlar? ¿O qué ocurriría si hubiera manipulaciones de fechas más complicadas? Las cosas pueden complicarse mucho cuando se manipulan y analizan fechas y horas, y bibliotecas como moment y date-fns simplifican esto de manera significativa.

Todo es 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.