En este codelab, mejorarás el rendimiento de la siguiente aplicación quitando las dependencias que no se usan y que no son necesarias.
Medir
Siempre es una buena idea medir el rendimiento de un sitio web antes de agregar optimizaciones.
- Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona Pantalla completa .
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. 🐈
- Presiona "Control + Mayúsculas + J" (o "Comando + Opción + J" en Mac) para abrir DevTools.
- Haga clic en la pestaña Red.
- Selecciona la casilla de verificación Inhabilitar caché.
- Vuelve a cargar la app.
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 entradaFilter
.
- Consulta la advertencia que se muestra.
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 sin usar que puedes 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 en las que puede haber una alternativa más sencilla. 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 utilidades 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 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 agrupador 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 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.
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 | Tamaño antes de cualquier reducción o compresión. |
---|---|
Tamaño analizado | Tamaño del paquete real dentro del paquete después de su compilación. 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 en Gzip | Es el tamaño del paquete después de que se comprime con codificación gzip. Este tema se trata en una guía aparte. |
Con la herramienta webpack-bundle-analyzer, es más fácil identificar los paquetes sin usar o innecesarios que conforman un gran porcentaje del paquete.
Cómo quitar paquetes sin utilizar
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 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;
Ahora, 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:
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 superficie 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 diferentes partes de sus paquetes de forma selectiva. Sin realizar mucho trabajo, actualizar las importaciones de la biblioteca 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, la importación de partes de la biblioteca moment
no se puede realizar con tanta facilidad, pero tal vez es posible quitarla por completo.
El cumpleaños de cada gatito se almacena en formato Unix (milisegundos) en la base de datos de Firebase.
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 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 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.