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 imagen para Angular. La directiva se lanzó recientemente para la versión preliminar para desarrolladores como parte de Angular v14.2. En esta publicación, se explica cómo la nueva directiva de imagen, NgOptimizedImage, admite la optimización de imágenes en Angular.

Segundo plano

Las imágenes son un componente común y fundamental de la experiencia del usuario web, ya que el 99.9% de las páginas web generan solicitudes para una o más imágenes. Las imágenes también son los elementos que más contribuyen al peso de la página, ya que representan una mediana de 982 kilobytes por página.

Debido a su cantidad y tamaño crecientes, las imágenes pueden obstaculizar el rendimiento de las páginas web y afectar las métricas de las Métricas web esenciales. En el 79.4% de las páginas para computadoras, una imagen fue el elemento de procesamiento de imagen con contenido más grande (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 frameworks 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 pruebas para determinar si mejorar la experiencia del desarrollador (DX) de la optimización de imágenes podría generar mejoras de rendimiento en 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 la LCP (de 2.4 s a 1.7 s) después de comenzar a usar next/image. La adopción posterior de next/image en la comunidad contribuyó al aumento de los orígenes de Next.js que cumplen con los umbrales de LCP. Pronto hubo solicitudes de funciones similares en otros frameworks, uno de los cuales es Angular.

Como resultado, Aurora consultó con Angular y Nuxt para 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 imagen de Angular (NgOptimizedImage) para llevar los parámetros de configuración predeterminados de optimización de imágenes a Angular.

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 en dispositivos móviles lo usan y cuenta con casi 3 millones de descargas semanales en NPM.

LCP para sitios web de Angular en el último año

Si observamos las puntuaciones de las Métricas web esenciales, el porcentaje de orígenes de Angular que cumplen con los umbrales de LCP "buenos" aún necesita trabajo. Solo el 18.74% de los sitios de Angular tenían 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 de LCP no optimizadas podrían ser una de las principales causas de un LCP más bajo 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 imagen de Angular se basa en las lecciones de los componentes de imagen que Aurora creó hasta la fecha y, al mismo tiempo, 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 abordaron de las siguientes maneras:

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

Los aspectos más destacados del diseño son los siguientes:

  1. Carga diferida inteligente

    Las imágenes que son invisibles para el usuario cuando se carga la página (por ejemplo, las imágenes de la mitad inferior de la página o las imágenes ocultas del carrusel) idealmente deberían cargarse de forma diferida. La carga diferida libera recursos del navegador para cargar otros textos, elementos multimedia o secuencias de comandos esenciales. La mayoría de las imágenes no son esenciales y deben cargarse de forma diferida, pero solo el 7.8% de las páginas usó 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 de forma inmediata las imágenes marcadas especialmente como priority. Esto garantiza que la mayoría de las imágenes tengan un comportamiento de carga óptimo.

  2. Priorización de imágenes críticas

    Agrega sugerencias de recursos (p.ej., preload o preconnect) para priorizar la carga de imágenes esenciales es una práctica recomendada. Sin embargo, la mayoría de las apps no los usan. Según el Almanaque Web de 2021, solo el 12.7% de las páginas para dispositivos móviles usan sugerencias de preconexión y solo el 22.1% de las páginas para dispositivos móviles usan sugerencias de carga previa.

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

    • Establece el atributo fetchpriority de la imagen en "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 de recurso preconnect que corresponde 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 espera. Si no está marcado como priority, se genera un error que le indica al desarrollador que agregue el atributo priority a la imagen de LCP.

    En última instancia, esta combinación de automatización y cumplimiento garantiza que la imagen de LCP tenga una sugerencia preconnect, un valor de atributo fetchpriority de high y que 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 imágenes, ya que proporciona una experiencia del 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 debes definir el nombre del recurso en el 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 imagen 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 image proporciona cargadores integrados con una configuración óptima para las CDN de imágenes más populares. Estos cargadores formatean las URLs de las imágenes automáticamente para garantizar que se usen el formato de imagen y la configuración de compresión recomendados para cada CDN.

  4. Errores y advertencias integrados

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

    1. Imágenes sin tamaño: La directiva de imagen muestra un error si el marcado de imagen no tiene definido 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 de Cambio de diseño acumulado (CLS) de la página. La práctica recomendada para evitar esto es que las imágenes tengan especificados los atributos width y height.

    2. Proporció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 está cerca de la relación de aspecto real de la imagen renderizada. Esto puede provocar que la imagen se vea distorsionada en la pantalla. Esto puede ocurrir en los siguientes casos:

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

    4. Densidad de la imagen: La directiva mostrará un error si intentas incluir una imagen en el srcset con una densidad de píxeles superior a 3x. Por lo general, no se recomiendan descriptores superiores a 2x, ya que tienen la consecuencia no deseada de forzar a los dispositivos móviles de alta resolución a descargar imágenes enormes. Además, el ojo humano no puede distinguir una gran diferencia por encima de 2 veces.

Desafíos

Adaptar las estrategias de optimización de imágenes para que funcionen en un framework del cliente fue un desafío principal cuando se diseñó NgOptimizedImage. La experiencia de renderización predeterminada en Next.js es la renderización del servidor (SSR) o la generación de sitios estáticos (SSG), mientras que la de Angular es la renderización del cliente (CSR). Aunque Angular admite una biblioteca de SSR (angular/universal), la mayoría de las apps de Angular (~60%) usan CSR.

La directiva image se compila por completo para que 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 crear optimizaciones específicas para las apps de CSR.

Estos son algunos de los desafíos encontrados:

  1. Cómo admitir sugerencias de recursos

    La carga previa de recursos críticos ayuda al navegador a detectarlos antes. Sin embargo, incluir sugerencias de recursos en apps de Angular es complicado porque:

    Adición manual: Es difícil para los desarrolladores agregar la sugerencia de recursos 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 cada ruta (al menos en el tiempo de publicación). Si agregas cualquier sugerencia de preload a <head>, el recurso se precargará para todas las rutas, incluso cuando no sea necesario. Por lo tanto, no se recomienda agregar sugerencias de preload de forma manual.

    Adición automática durante la renderización: No es útil usar el framework para agregar sugerencias de carga previa al encabezado del documento durante la renderización en una app de CSR. Dado que la renderización se produce después de que se descarga y ejecuta JavaScript, <head> se renderizará demasiado tarde para que tenga algún valor.

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

  2. Optimiza el tamaño y el formato de las imágenes en el servidor

    Como las apps de Angular suelen renderizarse 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 comprimirlas y convertirlas en formatos modernos, como WebP o AVIF, a pedido.

    Si bien la directiva no aplica el uso de CDN de imágenes, se recomienda usarlos con la directiva, y sus cargadores integrados se aseguran de que se usen las opciones de configuración correctas.

Impacto

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

Sitio web uno: Usa elementos <img> nativos con imágenes que se entregan a través de la CDN de Imgix (con opciones de configuración predeterminadas).

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

Comparación de tiras de imágenes: 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 del rendimiento de la directiva de imagen en aplicaciones empresariales reales de Angular.

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

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

Hoja de ruta futura

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

  • Mejor compatibilidad con las 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.

  • Inyección automática de sugerencias de recursos

    Es posible que se pueda integrar con la CLI de Angular para generar etiquetas de preconexión y precarga para imágenes LCP críticas.

  • Compatibilidad con SSR de Angular

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

  • Mejoras en la experiencia de los desarrolladores

    NgOptimizedImage requiere que se especifiquen los atributos width y height para cada imagen. Sin embargo, especificarlos para cada imagen puede ser agotador para algunos desarrolladores. Hay una posibilidad de mejorar la experiencia del desarrollador en la siguiente iteración de la siguiente manera:

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

Conclusión

La directiva de imagen de Angular estará disponible para los desarrolladores en etapas, comenzando con la versión preliminar para desarrolladores en la v14.2.0. Prueben NgOptimizedImage y dejen comentarios.

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