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

Karla Erickson
Kara Erickson
Elena Sohoni
Laena Sohoni

En mayo de 2022, los equipos de Aurora y Angular anunciaron que colaborarían en una directiva de imágenes para Angular. La directiva se lanzó recientemente para la vista previa para desarrolladores como parte de Angular v14.2. En esta publicación, se explica cómo la nueva directiva de imágenes, 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 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 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 las 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 convirtió 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 es un campo de prueba para determinar si mejorar la experiencia del desarrollador (DX) de la optimización de imágenes podría generar mejoras en el rendimiento para más apps que usan frameworks.

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

Como resultado, Aurora consultó a Angular y Nuxt a fin de crear prototipos de componentes de imágenes para estos frameworks. El componente de imagen Nuxt se lanzó el año pasado. Se lanzó la directiva de imágenes de Angular (NgOptimizedImage) para que los valores predeterminados de optimización de imágenes se apliquen a Angular.

Opportunity

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

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

Si se observan las puntuaciones de las Métricas web esenciales, el porcentaje de orígenes de Angular que alcanzan 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 LCP no optimizadas podrían ser una de las principales causas de un LCP deficiente en los sitios web de Angular.

La directiva de imágenes de Angular se diseñó para ayudar a mejorar estos números.

MVP para la directiva NgOptimizedImage

El MVP de la directiva de imágenes de Angular se basa en las lecciones de los componentes de imagen que Aurora ha creado 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 estándar de optimización de imágenes se han abordado de las siguientes maneras:

  • Proporcionar valores predeterminados seguros
  • Arrojar 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

    Lo ideal es que las imágenes que son invisibles para el usuario durante la carga de la página (por ejemplo, las imágenes de la mitad inferior de la página o las imágenes de carrusel ocultas) se cargan de forma diferida. La carga diferida libera los recursos del navegador para cargar otro texto, contenido multimedia o secuencias de comandos importantes. La mayoría de las imágenes no son fundamentales y deben cargarse de forma diferida, pero solo el 7.8% de las páginas usaron la carga diferida nativa en 2021.

    La directiva de imágenes de Angular carga de forma diferida las imágenes que no son críticas de forma predeterminada y solo carga con anticipación las imágenes especialmente marcadas como priority. Esto garantiza que la mayoría de las imágenes tengan 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 informe 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 las usa.

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

    • Establece el valor de 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 de 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 LCP se haya marcado como priority como se espera. Si no está marcado como priority, se mostrará un error que le indicará 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 de LCP tenga una sugerencia preconnect, un valor de atributo fetchpriority de high y que no tenga carga diferida.

  3. Configuración optimizada para herramientas de imágenes 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 la URL base en tu configuración. Una vez configurado, solo debes 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 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 de imágenes proporciona cargadores integrados con una configuración óptima para las CDN de imágenes más populares. Estos cargadores darán formato a las URLs de imágenes automáticamente para garantizar que se use la configuración de compresión y formato de imagen recomendados para cada CDN.

  4. Errores y advertencias integrados

    Además de las optimizaciones integradas anteriores, la directiva también incluye 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 muestra un error si el lenguaje de marcado de la imagen no tiene definidos un ancho y una altura explícitos. Las imágenes sin tamaño pueden provocar cambios de diseño, que afectan 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 deben tener los atributos width y height especificados.

    2. Relación de aspecto: La directiva de imagen muestra un error que informa 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 suceder

      1. Definiste las dimensiones incorrectas (ancho o alto) por error
      2. Si definiste una dimensión por porcentaje en tu CSS, pero no en 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 elemento srcset y la imagen intrínseca es significativamente 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 arrojará un error si intentas incluir una imagen en srcset con una densidad de píxeles superior a 3x. Generalmente, no se recomiendan los descriptores superiores a 2x, ya que tienen la consecuencia involuntaria de forzar a los dispositivos móviles de alta resolución a descargar imágenes de gran tamaño. Además, el ojo humano en realidad no puede distinguir una gran diferencia superior a 2 veces.

Desafíos

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

La directiva de imagen está completamente compilada para que la 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 aplicaciones de CSR.

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

  1. Sugerencias de recursos complementarios

    La precarga de los 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:

    Incorporació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 todas las rutas del sitio web. Por lo tanto, el <head> del documento es el mismo para todas las rutas (al menos en el momento de la publicación). Si agregas cualquier sugerencia preload a <head>, el recurso se precargaría para todas las rutas, incluso cuando no sea necesario. Por lo tanto, no se recomienda agregar sugerencias preload de forma manual.

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

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

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

    Dado que las apps de Angular se renderizan normalmente del lado del cliente, las imágenes en el 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 las CDN de imágenes, se recomienda usarlas 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 generar 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 las opciones de configuración predeterminadas).

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

Comparación de tiras 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 rendimiento de la directiva de imágenes 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 obtener resultados que las aplicaciones reales podrían ver.

Se realizaron pruebas de laboratorio de Lighthouse en su entorno de QA antes y después de usar la directiva de imágenes. En las computadoras de escritorio, su LCP promedio disminuyó de 12.0 s a 3.0 s, lo que representa 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 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 futuras versiones, entre ellas:

  • Mejor compatibilidad con imágenes responsivas:

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

  • Inserción automática de sugerencias de recursos

    Es posible realizar la integración con la CLI de Angular a fin de generar etiquetas de preconexión y carga previa para imágenes LCP críticas.

  • Compatibilidad con SSR de Angular

    La versión MVP está diseñada teniendo en cuenta las restricciones de la CSR de Angular, pero también será importante explorar las soluciones de optimización de imágenes para la 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, especificar estos valores para cada imagen puede resultar tedioso para algunos desarrolladores. Se puede mejorar la experiencia del desarrollador en este caso 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 "fill" en Next.js) que no requiere definir el ancho o la altura explícitos.
    2. Usar la integración de la CLI para establecer automáticamente el ancho y el alto 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 en etapas para los desarrolladores, comenzando con la versión preliminar para desarrolladores en la versión 14.2.0. Inténtalo con NgOptimizedImage y deja comentarios.

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