Cómo optimizar imágenes con la directiva de imágenes de Angular

Kara Erickson
Kara Erickson
Leena Sohoni
Leena Sohoni

En mayo de 2022, los equipos de Aurora y Angular anunciaron que colaborarían en una directiva de imágenes para Angular. Recientemente, se lanzó la directiva para la versión preliminar para desarrolladores como parte de la versión 14.2 de Angular. En esta publicación, se explica cómo la nueva directiva de imagen, NgOptimizedImage, admite la optimización de imágenes en Angular.

Información general

Las imágenes son un componente común y crucial de la experiencia del usuario en la Web. El 99.9% de las páginas web genera solicitudes de una o más imágenes. Las imágenes también son los factores que más contribuyen al peso de las páginas, ya que representan una mediana de 982 kilobytes por página.

Debido a su creciente cantidad y tamaño, las imágenes pueden dificultar el rendimiento de las páginas web y afectar las métricas de Métricas web esenciales. En el 79.4% de las páginas para computadoras de escritorio, una imagen fue el elemento Largest Contentful Paint (LCP) en 2021. Por lo tanto, la búsqueda de imágenes optimizadas se ha convertido en un esfuerzo constante para muchos de nosotros.

El equipo de Aurora cree en aprovechar el poder de los marcos de trabajo para proporcionar soluciones integradas a los desafíos comunes de los desarrolladores. Su primera incursión en el espacio de optimización de imágenes fue el componente de imagen de Next.js. Consideraron que este componente era un campo de prueba para determinar si mejorar la experiencia del desarrollador (DX) de la optimización de imágenes podría generar un aumento en el rendimiento de más apps que usan frameworks.

El primer conjunto de resultados del usuario de Next.js Leboncoin fue alentador. Leboncoin observó una mejora significativa en el LCP (de 2.4 s a 1.7 s) después de que empezara a usar next/image. La posterior adopción de next/image en la comunidad desempeñó un papel en el aumento de los orígenes de Next.js que cumplieron con los umbrales de LCP. Pronto hubo solicitudes para funciones similares en otros frameworks, y una de ellas era Angular.

Como resultado, Aurora consultó a Angular y Nuxt con el fin de crear prototipos de componentes de imagen para estos frameworks. El componente de imagen de Nuxt se lanzó el año pasado. Ahora se lanzó la directiva de imágenes de Angular (NgOptimizedImage) para que la optimización de imágenes se adapte a Angular de manera predeterminada.

Oportunidad

Angular es uno de los frameworks de JavaScript líderes que usan los desarrolladores en la actualidad. Más de 50,000 de los orígenes rastreados por HTTPArchive lo usan en dispositivos móviles y ofrece cerca de 3 millones de descargas semanales en NPM.

LCP de los sitios web de Angular durante el último año.

Si se observan las puntuaciones de las Métricas web esenciales, se debe mejorar el porcentaje de orígenes de Angular que cumplen con los umbrales de LCP “buenos”. Solo el 18.74% de los sitios de Angular tuvieron un buen LCP en dispositivos móviles en junio de 2022. Dado que las imágenes son el elemento LCP de más del 70% de las páginas web en dispositivos móviles y computadoras de escritorio, las imágenes LCP no optimizadas podrían ser una de las principales causas de un LCP más deficiente en los sitios web de Angular.

La directiva de imagen de Angular se diseñó para ayudar a mejorar estas cifras.

MVP para la directiva NgOptimizedImage

El MVP de la directiva de imágenes de Angular se basa en lecciones de los componentes de imagen que Aurora compiló hasta la fecha, a la vez que adapta el diseño a la experiencia de renderización del cliente de Angular. Muchos de los problemas de optimización de imágenes estándar se solucionaron de la siguiente manera:

  • Proporcionar valores predeterminados sólidos
  • Arrojar errores o advertencias para garantizar el cumplimiento de las prácticas recomendadas.

Los aspectos destacados del diseño son los siguientes:

  1. Carga diferida inteligente

    Lo ideal es que las imágenes que son invisibles para el usuario durante la carga de la página (por ejemplo, imágenes en la mitad inferior de la página o imágenes de carrusel ocultas) se carguen de forma diferida. La carga diferida libera recursos del navegador para cargar otros textos, archivos multimedia o secuencias de comandos importantes. La mayoría de las imágenes no son fundamentales y deberían cargarse de forma diferida, pero solo el 7.8% de las páginas utilizó la carga diferida nativa en 2021.

    La directiva de imagen de Angular carga de forma diferida las imágenes no críticas de forma predeterminada y solo carga con anticipación las imágenes marcadas especialmente como priority. Esto garantiza que la mayoría de las imágenes muestren un comportamiento de carga óptimo.

  2. Priorización de imágenes fundamentales

    Agregar sugerencias de recursos (p.ej., preload o preconnect) para priorizar la carga de imágenes críticas es una práctica recomendada. Sin embargo, la mayoría de las apps no las usan. Según el Almanac web de 2021, solo el 12.7% de las páginas para dispositivos móviles usa sugerencias de preconexión y solo el 22.1% de las páginas para dispositivos móviles usa sugerencias de precarga.

    La directiva de imagen actúa en dos frentes cuando las imágenes se marcan como prioridad.

    • Establece la fetchpriority de la imagen como "high" para que el navegador sepa que debe descargar la imagen con una prioridad alta.
    • En el modo de desarrollo, una verificación del entorno de ejecución confirma que se incluyó una sugerencia del recurso preconnect correspondiente al origen de la imagen.

    En el modo de desarrollo, la directiva también usa la API de PerformanceObserver para verificar que la imagen de LCP se haya marcado como priority como se esperaba. Si no está marcado priority, se genera un error que le indica al desarrollador que agregue el atributo priority a la imagen LCP.

    En última instancia, esta combinación de automatización y cumplimiento garantiza que la imagen LCP tenga una sugerencia preconnect, un valor de atributo fetchpriority de high y no se cargue de forma diferida.

  3. Configuración optimizada para herramientas de imagen populares

    Se recomienda que las aplicaciones de Angular usen CDN de imágenes, que suelen proporcionar servicios de optimización de forma predeterminada.

    La directiva fomenta el uso de CDN de imagen, ya que proporciona una experiencia de desarrollador (DX) especialmente atractiva para configurarlas en la app. Admite una API de cargador que te permite definir el proveedor de CDN y tu URL base en la configuración. Una vez configurado, solo tienes que definir el nombre del recurso en el lenguaje de marcado. Por ejemplo,

    // in module providers:
    provideImgixLoader('https://mysite.net/assets/')
    
    // in markup
    <img ngSrc="image.png" >
    <img ngSrc="image2.png" >
    

    Esto equivale a incluir las siguientes etiquetas de imágenes y reduce el lenguaje de marcado que los desarrolladores deben incluir para cada imagen.

    <img src="https://mysite.net/assets/image.png">
    <img src="https://mysite.net/assets/image2.png">
    

    La directiva de imagen proporciona cargadores integrados con configuración óptima para las CDN de imágenes más populares. Estos cargadores formatearán las URLs de imagen automáticamente para garantizar que se usen los parámetros de configuración de compresión y formato de imagen recomendados para cada CDN.

  4. Errores y advertencias integrados

    Además de las optimizaciones integradas mencionadas anteriormente, la directiva también tiene verificaciones integradas para garantizar que los desarrolladores hayan seguido las prácticas recomendadas en el lenguaje de marcado de imágenes. La directiva de imagen realiza las siguientes verificaciones.

    1. Imágenes sin tamaño: La directiva de imagen arroja un error si el lenguaje de marcado de imágenes no tiene definidos un ancho y una altura explícitos. Las imágenes sin tamaño pueden provocar cambios de diseño, lo que afecta la métrica Cambio de diseño acumulado (CLS) de la página. Para evitarlo, se recomienda que las imágenes tengan los atributos width y height especificados.

    2. Relación de aspecto: La directiva de imagen arroja un error para informar a los desarrolladores si la relación de aspecto de width:height definida en el HTML no es cercana a la relación de aspecto real de la imagen renderizada. Esto puede hacer que la imagen se vea distorsionada en la pantalla. Esto puede ocurrir si

      1. Definiste las dimensiones incorrectas (ancho o alto) por error o
      2. Si definiste una dimensión por porcentaje en tu CSS, pero no la otra (por ejemplo, width: 100% necesita height: auto para asegurarse de que la imagen crezca en ambas dimensiones).
    3. Imágenes de gran tamaño: Si la imagen no define un elemento srcset y la imagen intrínseca es significativamente más grande que la imagen renderizada, la directiva mostrará una advertencia que sugerirá el uso de los atributos srcset y sizes.

    4. Densidad de la imagen: La directiva arrojará un error si intentas incluir una imagen en srcset con una densidad de píxeles superior a 3x. Por lo general, no se recomiendan los descriptores con un valor superior a 2x porque tienen la consecuencia no deseada de forzar a los dispositivos móviles de alta resolución a descargar imágenes grandes. Además, el ojo humano no puede distinguir muchas diferencias superiores al doble.

Desafíos

Uno de los desafíos principales del diseño de NgOptimizedImage fue adaptar las estrategias de optimización de imágenes para que funcionen dentro de un marco de trabajo del cliente. La experiencia de renderización predeterminada en Next.js es Server Side Rendering (SSR) o Static Site Generation (SSG), mientras que en Angular es la renderización del cliente (CSR). Aunque Angular admite una biblioteca SSR (angular/universal), la mayoría de las apps de Angular (alrededor del 60%) usan CSR.

La directiva de imagen se creó completamente para que el CSR se alinee con el caso de uso típico en las apps de Angular. Esto estableció restricciones adicionales, y el equipo tuvo que repensar cómo compilar optimizaciones específicas para las aplicaciones de CSR.

Estos son algunos de los desafíos que se encontraron:

  1. Sugerencias de recursos de asistencia

    La precarga de recursos críticos ayuda al navegador a descubrirlos antes. Sin embargo, incluir sugerencias de recursos en las apps de Angular es complicado por los siguientes motivos:

    Adición manual: Es difícil para los desarrolladores agregar la sugerencia del recurso preload de forma manual. Angular usa un archivo index.html compartido para todo el proyecto o para todas las rutas del sitio web. Por lo tanto, el <head> del documento es el mismo para todas las rutas (al menos al momento de la entrega). Agregar cualquier sugerencia de preload a <head> implicaría que el recurso se precargaría para todas las rutas, incluso en las que no es obligatorio. Por lo tanto, no se recomienda agregar sugerencias de preload de forma manual.

    Agregación automática durante la renderización: No se recomienda usar el framework para agregar sugerencias de precarga al encabezado del documento durante la renderización en una app de CSR. Dado que la renderización ocurre después de que se descarga y ejecuta JavaScript, el <head> se renderizará demasiado tarde para no tener ningún valor.

    En la primera versión de la directiva, sirve una combinación de sugerencias preconnect y fetchpriority para priorizar la imagen en lugar de preload. Sin embargo, actualmente Aurora está trabajando con el equipo de la CLI de Angular para habilitar la inserción automática de sugerencias de recursos en el tiempo de compilación. ¡Mantente alerta!

  2. Optimiza el tamaño y el formato de la imagen en el servidor

    Como las apps de Angular se suelen renderizar del lado del cliente, las imágenes del sistema de archivos no se pueden comprimir en el momento de la solicitud y se entregan tal como están. Por este motivo, se recomienda usar CDN de imágenes para comprimir imágenes y convertirlas a formatos modernos como WebP o AVIF a pedido.

    Si bien la directiva no aplica de manera forzosa el uso de CDN de imágenes, te recomendamos que las uses con la directiva, y sus cargadores integrados garantizan que se usen las opciones de configuración correctas.

Impacto

En la siguiente demostración, se muestra la diferencia que la directiva de imágenes de Angular puede marcar en el rendimiento de las imágenes. Compara dos sitios web:

Website One: Usa elementos <img> nativos con imágenes entregadas a través de la CDN de Imgix (con opciones de configuración predeterminadas).

Sitio web dos: Usa la directiva de imagen para todas las imágenes. También incluye las optimizaciones que recomiendan directamente las advertencias o los errores que arroja la directiva.

Comparación de la tira de película: Sitio web uno con etiquetas de imagen nativas en comparación con el sitio web dos con la directiva de imagen de Angular.

El equipo trabajó con socios para validar el impacto de la directiva de imagen en el rendimiento en las aplicaciones empresariales reales de Angular.

Uno de estos socios fue Land's End. Se esperaba que su sitio fuera un buen caso de prueba de resultados que podrían ver las aplicaciones reales.

Se realizaron pruebas de laboratorio con Lighthouse en su entorno de QA antes y después de usar la directiva de imagen. En computadoras, el LCP medio disminuyó de 12.0 s a 3.0 s, una mejora del 75% en el LCP. En dispositivos móviles, el LCP medio disminuyó de 20.2 s a 12.0 s (mejora del 40.6%).

Hoja de ruta para el futuro

Esta es solo la primera parte del diseño de la directiva de imagen de Angular. Hay muchas otras funciones planificadas para versiones futuras, incluidas las siguientes:

  • Mejor compatibilidad con imágenes responsivas:

    Actualmente, NgOptimizedImage admite el uso de srcset, pero los atributos srcset y sizes deben proporcionarse de forma manual para cada imagen. En el futuro, la directiva podría generar los atributos srcset y sizes automáticamente.

  • Inserción automática de sugerencias de recursos

    Podría ser posible realizar la integración con la CLI de Angular a fin de generar etiquetas de conexión previa y precarga para imágenes de LCP críticas.

  • Compatibilidad con el SSR de Angular

    La versión de MVP se diseñó teniendo en cuenta las restricciones de la CSR de Angular, pero también será importante explorar soluciones de optimización de imágenes para el SSR de Angular (angular/universal).

  • Mejoras en la experiencia del desarrollador

    NgOptimizedImage requiere que se especifiquen los atributos width y height para cada imagen. Sin embargo, especificarlas para cada imagen puede resultar tedioso para algunos desarrolladores. Existe el potencial de mejorar la experiencia del desarrollador en la próxima iteración de la siguiente manera:

    1. Admite un modo adicional (similar a la opción de diseño de imagen de "fill" en Next.js) que no requiere que se defina el ancho o la altura explícitos.
    2. Usa la integración de la CLI para establecer automáticamente el ancho y la altura de las imágenes locales mediante la determinación de las dimensiones reales de la imagen.

Conclusión

La directiva de imágenes de Angular estará disponible para los desarrolladores en etapas a partir de la versión preliminar para desarrolladores, que se encuentra en la versión 14.2.0. Prueba NgOptimizedImage y envíanos tus comentarios

Agradecemos especialmente a Katie Hempenius y Alex Castle por su contribución.