Como mejoré 20% la velocidad de carga de esta página
Desde que desarrollé esta página yo sabía que había ciertos problemas de performance y que en algún momento tenía que arreglarlo, ese momento fue ayer.
Para saber que mejorar hay que medir
Usando Google PageSpeed Insights, una herramienta de Google Chrome que informa sobre el rendimiento de una página en dispositivos móviles y de escritorio, y ofrece sugerencias sobre cómo se puede mejorar esa página.
Corriendo Google PageSpeed Insights en esta página inmediatamente notamos que tiene ciertos problemas importantes de rendimiento, veamos los resultados.
Un 77 de performance no es un buen resultado (por eso está en amarillo 😂) y esto es precisamente lo que quiero arreglar, pero para saber como arreglarlo tengo que verlo más de cerca.
Mirando de cerca las métricas
En el reporte de Google PageSpeed Insights pude ver a más detalle cuáles son los problemas que tiene la página para que el rendimiento esté en apenas 77 de 100.
En el detalle de las métricas pude ver que el Time to Interact y el Total Blocking Time eran muy altos, 5.7 segundos y 850 milisegundos respectivamente.
En la siguiente imagen podemos ver que hay dos métricas que están mal (amarillo y rojo):
Time to Interact
El time to interact mide la cantidad de tiempo que le toma a la página a hacerse completamente interactivo. Y según los estándares de Google:
- 🟩 Entre 0 y 3.8 segundos se considera rápido (lo que queremos)
- 🟨 Entre 3.9 y 7.3 segundos se considera moderadamente lento
- 🟥 Más de 7.3 se considera lento
Total Blocking Time
El total blocking time mide la cantidad total de tiempo que pasa bloqueado el hilo principal lo suficiente para causar que el usuario no pueda interactuar con la página.
Esta medida la hace entre que se “pintan” los primeros elementos de la página (First Contentful Paint) y el Time to interact.
- 🟩 Entre 0-200 milisegundos se considera rápido (lo que queremos)
- 🟨 Entre 200-600 milisegundos se considera moderadamente lento
- 🟥 Más de 600 milisegundos se considera lento
¿Cómo arreglo eso?
Google PageSpeed Insights me da recomendaciones para mejorar cada uno de los puntos que están mal en mi página.
Para Time to Interact me dice que tengo que:
- Minimizar el trabajo del hilo principal
- Reducir el tiempo de ejecución de JavaScript
Y para Total Blocking Time me recomienda que tengo
- Revisar si tengo carga, análisis o ejecución de JavaScript innecesarios
- Declaraciones de JavaScript ineficientes
Ya con esta información puedo saber o sospechar que en esta página tengo demasiado JavaScript ejecutandose o que tengo mucho código JavaScript ineficiente.
Me convierto en detective
Empiezo a pensar que tengo en esta página que requiere ejecutar mucho JavaScript. Al principio no se me ocurre nada porque es una página de un blog, son solo texto e imágenes, nada del otro mundo, pero además esta página se genera estáticamente con Next.js.
Usando el tab de Performance
El tab de performance del Web Inspector me permite evaluar como se ejecuta el JavaScript cuando mi página carga. Abro el Web Inspector voy al Performance tab y hago click en “Reload”.
En el resultado puedo ver inmediatamente que tengo un “Long tasks”.
Una tarea larga es un código JavaScript que monopoliza el hilo principal durante largos periodos de tiempo, haciendo que la interfaz de usuario se congele
Fuente: Are long JavaScript tasks delaying your Time to Interactive?
Luego en el tab de Bottom-Up que sirve para ver qué actividades ocupan directamente el mayor tiempo en conjunto puedo ver que el código en el archivo prism-core.js es el que toma más tiempo en ejecutarse.
¿Qué es prism?
Prism es una librería que se utiliza para hacer syntax highlight de los ejemplos de código en mis post de blog. Ahora tengo que conseguir quien la usa.
Encontrando el culpable
Yo no uso Prism directamente, entonces seguramente tengo una librería que si lo usa. Lo que hice fue ir adentro en el código de la página y empiezo a revisar dentro de los archivos que estoy importando a ver si consigo algo extraño y...
Lo conseguí, react-syntax-highlighter es la librería que estoy usando para hacer el syntax hightlight de los bloques de código y por debajo usa prims.
Como nos muestra Import Cost, pesa 187kb gzipped, eso es demasiado. Así que tiene sentido que esta librería sea el problema. Import Cost es una extensión de VsCode que te permite identificar imports en tus archivos de JavaScript o Typescript que sean muy pesados.
¿Es realmente culpable?
Hasta ahora react-syntax-highlighter se ve bien sospechoso, pero hasta que no pruebe no puedo saber si es realmente el culpable.
Como dije, esta librería es solo para renderizar bloques de código, así que puedo quitarla y renderizar con los bloques con <pre> y <code> para probar. Los bloques de código se van a ver sin syntax hightlight, pero es únicamente para probar.
Corro nuevamente Google Page Insights en la página y...
Efectivamente, react-syntax-highlighter es la culpable de, como canta el Sol de México Luis Miguel, todas mis angustias y todos mis quebrantos.
Buscando el reemplazo
Este es un blog técnico entonces va a tener muchos ejemplos de código, no puedo simplemente eliminar react-syntax-highlighter, necesito una alternativa.
Crear mi problema librería desde cero
Aunque esto es una alternativa, no es una buena, formatear código para que se vea bien es una tarea bien común porque lo que ya deben existir muchísimas librerías que hacen esto, escribir una de cero es una perdida de tiempo.
refractor
Es una librería para hacer formateo de código ligera, robusta, elegante y además usa por debajo Prims que es la misma librería que usaba react-syntax-highlighter. La manera como funciona es bastante directa:
- Se importa la librería
- Se llama al método highlight pasándole el código y el lenguaje
- Nos da un objeto json con el formato
El objeto json se ve así:
Pero yo no necesito un json yo necesito convertir eso en HTML. Para eso utilizo otra librería que se llama hast-util-to-html.
Esto me daría el HTML
Y este HTML está perfecto porque tiene las mismas clases que ya yo tengo para darle estilos al bloque de código y esto es resultado que ambas librerías refractor y react-syntax-highlighter utilizan Prism (otra librería más) por debajo.
Creando mi nuevo component
Para encapsular todo esto lo mejor es que cree un component de React que reciba el código y el lenguaje y formatee todo, así puedo reusarlo cuantas veces sea necesario. Es un component bastante simple y su código quedó así:
dangerouslySetInnerHTML es el reemplazo de React para utilizar innerHTML en el DOM del navegador. Puedes leer más sobre él en la documentación de React.
Usando el component
Ya finalmente lo que me falta es usar mi nuevo component para renderizar los bloques de código:
¿Funcionó?
Google Page Insights
Ya teniendo la solución lista y corriendo, solo me queda asegurarme que efectivamente la performance mejoró, corro nuevamente Google Page Insights.
Performance Tab
Por ultimo corro nuevamente el “runtime performance analysis” en el Performance tab...
Perfecto, ya no tengo Long Tasks durante la carga, definitivamente react-syntax-highlighter era el culpable de la lentitud de la pagina.
Conclusión
Mejorar el tiempo de carga de la página de los posts de mi blog es importante, primero es importante para SEO, pero además tus usuarios lo agradecerán.
Lo primero que tenemos que hacer es medir e identificar los culpables. Con Google Page Insights pude determinar el problema y pude ver que es en JavaScript. Con el tab de Performance del Web Inspector pude identificar lo que parece ser la librería culpable y reemplazarla.