- Jampack es una herramienta de posprocesamiento que toma la salida de un Static Site Generator para optimizar la experiencia de usuario y las puntuaciones de Core Web Vitals; no es un bundler ni un framework
- Convierte
<img> y <picture> de HTML en imágenes responsivas, y agrega automáticamente formatos como WebP y AVIF, además de srcset, sizes, width, height, loading="lazy", decoding="async", etc.
- Las imágenes en CDN pueden volverse responsivas con
srcset basado en parámetros de URL, y las imágenes externas pueden descargarse bajo _jampack para convertirse en imágenes locales optimizadas
- Los recursos above-the-fold se procesan con alta prioridad y las imágenes pequeñas se insertan inline en el HTML, mientras que las imágenes e iframes below-the-fold se cargan de forma diferida
- Se aplica ejecutando
npx @divriots/jampack ./dist sobre la carpeta de salida del build del sitio estático, y en una segunda pasada también comprime CSS, JS, HTML, SVG e imágenes
Qué hace Jampack
- Jampack toma como entrada el resultado generado por un Static Site Generator, es decir, un SSG, y optimiza el sitio web estático
- El objetivo es mejorar la experiencia de usuario y las puntuaciones de Core Web Vitals
- El README diferencia a Jampack diciendo que “no es un bundler ni un framework”
- La introducción está disponible en Read the introduction blog post
Optimización de imágenes
- Un
<img> común se transforma en una imagen responsiva
- Genera un archivo WebP para el
src original y agrega srcset
- Añade atributos como
sizes="100vw", loading="lazy", decoding="async", width y height
- El elemento
<picture> se convierte en una estructura responsiva que incluye varios formatos de imagen
- Se agrega
<source type="image/avif"> para AVIF
- Se agrega
<source type="image/webp"> para WebP
- El
<img> original también recibe srcset, sizes, loading, decoding, width y height
- La función de optimización de imágenes remite a la documentación
optimize-images, pero el enlace correspondiente en el README es una ruta relativa
Manejo de imágenes CDN y externas
- Las imágenes de CDN pueden mantener la URL remota mientras se les agrega un
srcset responsivo
- El ejemplo crea varias opciones de ancho agregando a la URL de una imagen de Unsplash los parámetros
w, fit=min y auto=format
- La imagen original también recibe
loading="lazy", decoding="async" y sizes="100vw"
- Las imágenes externas pueden descargarse y convertirse luego en archivos locales optimizados
- El ejemplo cambia una imagen externa de Unsplash por una ruta como
_jampack/ab99b9d280ce4cf7cfc810b59f3a7739.jpg.webp
- La imagen convertida incluye
width, height, srcset, sizes, loading y decoding
Above-the-fold y optimización de CSS y enlaces
- Jampack optimiza por separado los recursos above-the-fold
- Las imágenes se cargan con mayor prioridad
- Las imágenes pequeñas se incrustan en el HTML
- Los recursos below-the-fold se cargan de forma diferida
- Las imágenes y los iframes son objetivos de lazy load
- El CSS crítico se inserta inline en el HTML
- El objetivo es evitar el FOUC que puede producirse durante la descarga y el parseo de la hoja de estilos
- El resto del CSS se carga de forma diferida
- El prefetch de enlaces sirve para acelerar la navegación a páginas futuras
- Puede procesarse dinámicamente cuando los enlaces entran en el viewport usando quicklink
Compresión de recursos y forma de ejecución
- Jampack comprime en una segunda pasada todos los recursos que no tocó antes, manteniendo el mismo nombre y el mismo formato
- Las herramientas de compresión por extensión son las siguientes
- Cuando el sitio web estático está en la carpeta
dist, se ejecuta con el siguiente comando
npx @divriots/jampack ./dist
- Las opciones adicionales pueden consultarse en CLI options
Casos de uso y significado del nombre
1 comentarios
Opiniones en Hacker News
Era justo la herramienta que estaba buscando. Para hacer este tipo de optimización de imágenes, venía escribiendo mis propios scripts basados en Sharp, pero Jampack los reemplaza por completo y funciona mucho mejor.
Después de compilar un sitio estático con Quarto y ejecutar Jampack, el tamaño de la carpeta se redujo 32%, y todavía no veo desventajas evidentes.
Según PageSpeed Insights, antes de Jampack en móvil tenía rendimiento 52, accesibilidad 73, prácticas recomendadas 100 y SEO 85; en escritorio, rendimiento 90, accesibilidad 75, prácticas recomendadas 100 y SEO 82.
Después de aplicarlo, dio rendimiento móvil 49, accesibilidad 80, prácticas recomendadas 100, SEO 92, y en escritorio rendimiento 85, accesibilidad 82, prácticas recomendadas 100, SEO 91.
También hay material que dice que “la mediana de 5 ejecuciones de Lighthouse es dos veces más estable que una sola ejecución”: https://developers.google.com/web/tools/lighthouse/variabili...
georges [at] divriots [dot] com
Me recuerda al módulo PageSpeed para Apache y Nginx: https://developers.google.com/speed/pagespeed/module
El repositorio de GitHub también fue archivado: https://github.com/apache/incubator-pagespeed-ngx
¿Quizá se movió a otro lado?
Vaya, esto me gusta bastante. Pienso probarlo.
Si a alguien le parece malo, me gustaría que señalara las fallas. A mis ojos se parece a compilar C a ensamblador ultraoptimizado, y parece una herramienta que se encarga bien de algo que no quiero hacer yo mismo.
Creo que, si escribimos el HTML y CSS más simple e intuitivo posible, el navegador de cualquier dispositivo simplemente debería renderizarlo bien.
Si de verdad hay que distribuir artefactos optimizados a ese nivel, sería mejor saltarse HTML y CSS por completo, distribuir WebAssembly altamente optimizado y dejar que los desarrolladores usen el lenguaje que quieran.
Estaría bueno que hubiera una forma de crear subconjuntos de fuentes según el rango Unicode de la salida del SSG, y de fijar ejes OpenType a partir de los font-feature-settings definidos en el CSS.
Me pregunto si eso es lo que querías decir con “fijar ejes OpenType basado en font-feature-settings”, o si te referías a otra cosa.
También me gustaría optimizar subconjuntos de fuentes, pero todavía no sé bien cuánto se podría mejorar. Me da curiosidad si lo has hecho manualmente.
Me parece interesante la idea de identificar el CSS crítico que debería ir inline en vez de en una hoja de estilos separada.
Esperaba que existiera una forma de distinguir por principio entre CSS crítico y no crítico. Por ejemplo, considerar siempre como no críticos los efectos de interacción del usuario como
:hover.Pero la biblioteca que usan renderiza la página y hace su mejor estimación de qué reglas pueden considerarse críticas, lo cual me deja un poco insatisfecho: https://github.com/GoogleChromeLabs/critters
Claro, si estás incluyendo fuentes inline, lo entiendo; pero si solo los estilos superan los 50 KB, en general vas por mal camino.
Hablando en serio, el inline es tremendamente bueno para el rendimiento incluso comparado con una caché caliente, y el umbral a partir del cual una hoja de estilos o script externo empieza a ser mejor es más alto de lo que uno cree; bajo criterios de mercado comunes, puede llegar a cientos de KB.
El concepto de CSS crítico me parece un enfoque derrotista para recuperar un poco del rendimiento desperdiciado en vez de arreglar el problema de fondo.
Dicho eso, no es una técnica sistemática, sino un juicio basado en experiencia y observaciones ligeras. Ojalá alguien mida mejor este concepto, aunque no creo que vaya a ser yo.
Esto parece cubrir varios de los usos por los que la gente elige SSG y plugins desde el principio. Especialmente si eliges Astro o Eleventy.
¿Hay alguna razón para preferir dejarlo como un paso separado después del build? Hace que los rebuilds durante el desarrollo sean más rápidos, pero parece un compromiso frente a la posibilidad de pasar por alto bugs sutiles al agregar cosas como declaraciones de width en imágenes.
Como alguien que odia trabajar en layouts de páginas web y se niega a aprenderlo, pero a veces tiene que hacerlo, esta herramienta se ve muy bien.
Se ve bien. Pero personalmente odio tener que esperar imágenes cuando hago scroll debajo del primer pantallazo de una página.
¿El comportamiento por defecto carga en segundo plano el resto del contenido inferior después de que termina el contenido del primer pantallazo?
loading="lazy"como “no cargues esta imagen/iframe hasta que esté casi visible”: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/im...Eso sí, como la relación de aspecto se inserta inline, el layout no cambia después de que termina de cargar. Es decir, evita el mayor pecado de la carga diferida.
loading="lazy"nativo del navegador.Actualmente no hay forma de cambiar este comportamiento, pero se podría agregar una opción para precargar en segundo plano las imágenes debajo del primer pantallazo una vez cargada toda la página. Es una idea bastante buena.
Aunque me preocupa que termine cargando también imágenes innecesarias al final de la página. Si es una opción, cada quien podría activarla o desactivarla, así que estaría bien.
¿Qué generadores de sitios estáticos usan en producción? Parece que esta herramienta podría optimizar aún más el resultado.
Por ejemplo, ayer pasé todo el día siguiendo ejemplos para convertir un sitio web en React de Divjoy a HTML simple y servirlo desde un bucket de S3. No pensé que fuera a ser tan difícil y todavía sigo perdido.
Idealmente, me gustaría algo que despliegue automáticamente a un bucket de S3 y hasta conecte el dominio. Me duele haber pagado y que el desarrollador haya desaparecido y el Discord esté abandonado. Por eso siempre prefiero FOSS.
En cierta medida, ya tienen algunas de estas funciones.
En uno de mis proyectos no hubo grandes cambios. Por ejemplo, el tamaño total del bundle bajó, pero el tamaño gzip subió, así que en la práctica para mí fue una pérdida neta.
Aun así, las mejoras de CSS sí parecen haber ayudado.
La idea se ve excelente, y si el proyecto hubiera tenido imágenes probablemente habría ayudado.
Puedes desactivar esa función configurando browserlist como una cadena vacía: https://jampack.divriots.com/features/browser-compatibility/