Novedades de la directiva NgOptimizedImage de Angular

Alex Castle
Alex Castle

Hace poco más de un año, el equipo de Chrome Aurora lanzó la directiva NgOptimizedImage de Angular. La directiva se enfoca principalmente en mejorar el rendimiento según las métricas de Métricas web esenciales. Incluye optimizaciones de imágenes comunes y prácticas recomendadas en una API para el usuario que no es mucho más complicada que un elemento <img> estándar.

En 2023, mejoramos la directiva con funciones nuevas. En esta publicación, se describen las funciones más sustanciales, con énfasis en por qué elegimos priorizar cada una y cómo puede ayudar a mejorar el rendimiento de las aplicaciones de Angular.

Nuevas funciones

NgOptimizedImage ha mejorado sustancialmente con el tiempo, incluidas las siguientes funciones nuevas.

Modo de relleno

Establecer el tamaño de las imágenes proporcionando los atributos width y height es una optimización muy importante para reducir el cambio de diseño, ya que los navegadores deben conocer la relación de aspecto de la imagen para ahorrar espacio. Sin embargo, ajustar el tamaño de las imágenes es un trabajo adicional para los desarrolladores de aplicaciones y no tiene sentido en algunos casos de uso de imágenes.

Ayudar a resolver esta tensión es la primera función importante que se agrega al componente de imagen posterior a la versión preliminar para desarrolladores: el modo de relleno. De esta forma, los desarrolladores pueden incluir imágenes sin cambiarles el tamaño explícitamente y sin incurrir en un cambio de diseño.

Con el modo de relleno, se inhabilita el requisito de tamaño de la imagen y se ajusta automáticamente el estilo de la imagen para llenar el elemento contenedor. Esto separa la relación de aspecto de una imagen del espacio que ocupa en la página y te brinda un mayor control sobre cómo se ajustan las imágenes al diseño de tu página.

El modo de relleno usa NgOptimizedImage como una alternativa de mejor rendimiento a la propiedad de CSS background-image. Coloca una imagen dentro de <div> o de otro elemento que hubiera tenido el estilo background-image y, luego, habilita el modo de relleno, como se muestra en el ejemplo de código anterior. Usa las propiedades de CSS object-fit y object-position en <div> para controlar cómo se posiciona la imagen en segundo plano.

// Height and width are required
<img ngSrc="example.com" height="300" width="400">

// Unless you use fill mode!
<div style="width: 100vw; height: 50em; position: relative">
  <img ngSrc="example.com" fill>
</div>

Generación de Srcset

Una de las técnicas de optimización de imágenes más eficaces es el uso del atributo srcset para garantizar que se descarguen imágenes del tamaño adecuado en cualquier dispositivo que acceda a tu aplicación. Si usas srcset en tu app, puedes evitar desperdiciar ancho de banda y mejorar sustancialmente tu LCP Core Web Vital.

La desventaja del atributo srcset es que puede resultar difícil de implementar. Escribir manualmente los valores de srcset significa agregar varias líneas de lenguaje de marcado a cada elemento de imagen de tu app, junto con varias URLs personalizadas para cada srcset. También debes decidir entre un conjunto de puntos de interrupción, lo cual es complicado, ya que pueden representar tanto las densidades de pantalla como los tamaños de viewport de los dispositivos comunes.

Es por eso que agregar la generación automatizada de srcset en la directiva de NgOptimizedImage fue un evento importante posterior al lanzamiento. Con esta incorporación, cualquier aplicación que utilice una CDN que admita el cambio de tamaño de imágenes puede obtener srcsets completas y personalizables, agregadas automáticamente a cada imagen generada con la directiva NgOptimizedImage.

Incluimos una API simplificada para configurar la propiedad sizes, que se usa para garantizar que cada imagen obtenga el tipo correcto de srcset. Si no incluyes un atributo sizes, sabemos que la imagen debe tener un tamaño fijo y debería obtener un srcset que depende de la densidad, como el siguiente:

<img src="www.example.com/image.png" srcset="www.example.com/image.png?w=400 1x, www.example.com/image.png?w=800 2x" >

Este tipo de srcset garantiza que las imágenes se muestren en un tamaño que tenga en cuenta la densidad de píxeles del dispositivo del usuario.

Por otro lado, si incluyes la propiedad sizes, NgOptimizedImage genera un srcset responsivo que incluye puntos de interrupción para muchos tamaños comunes de imágenes y dispositivos, usando esta lista predeterminada de interrupciones:

[16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840]

Generación de preconexión

Para mejorar el LCP, es importante reducir el tiempo que dedican los usuarios a descargar la imagen de LCP. En la sección anterior, viste cómo srcset puede ayudar con la transferencia de archivos de imagen más pequeños, pero una optimización igualmente importante es iniciar la transferencia lo antes posible. Una forma de hacerlo es usar etiquetas link rel="preconnect" para iniciar la conexión al dominio de tu imagen.

Desde el comienzo, NgOptimizedImage ha advertido si no puede preconectarse al dominio de su imagen de LCP, pero la advertencia no es la solución ideal; preferimos que solucionemos el problema por ti. Y eso es exactamente lo que NgOptimizedImage ahora, con la generación automatizada de preconexión.

Para admitir esta función, usamos análisis de código estático para intentar detectar dominios de imagen en cargadores de NgOptimizedImage y generar automáticamente etiquetas de vínculo de preconexión para esos dominios. Es posible que, de todos modos, haya casos en los que se requieran vínculos de preconexión manual, pero para la mayoría de los usuarios, la preconexión automática implica realizar un paso menos para lograr un buen rendimiento de la imagen.

Compatibilidad mejorada para cargadores personalizados

Un elemento clave de NgOptimizedImage es la arquitectura del cargador, que permite que la directiva genere automáticamente las URL adaptadas a la CDN de imagen de la aplicación. Se incluye un conjunto de cargadores integrados para las CDN más usadas. También proporcionamos el uso de cargadores personalizados, que te permiten integrar NgOptimizedImage con casi cualquier solución de hosting de imágenes.

En el lanzamiento, estos cargadores personalizados tenían un alcance limitado y solo podían leer el atributo width del elemento de imagen. En respuesta a los comentarios de los usuarios, agregamos compatibilidad con una estructura de datos loaderParams personalizable, que permite pasar datos arbitrarios del elemento de imagen al cargador personalizado. Con la expansión, los cargadores personalizados pueden ser tan simples o complejos como lo requiera la infraestructura de imagen de una aplicación.

En el siguiente ejemplo, se muestra cómo un cargador personalizado simple podría usar la API de loaderParams para seleccionar entre dos dominios de imagen alternativos:

const myCustomLoader = (config: ImageLoaderConfig) => {
  if (config.loaderParams?.alternateDomain) {
    return `https://alternate.domain.com/images/${config.src}`
  }
  return `https://primary.domain.com/images/${config.src}`;
};

Puedes encontrar un ejemplo de un cargador personalizado más complejo en la documentación de Angular.

Guía expandida para el rendimiento de las imágenes

Hasta ahora, todas las alertas de rendimiento de imágenes que agregamos a Angular formaban parte de la directiva NgOptimizedImage. Si no usas la directiva en la app, no recibirás orientación sobre los problemas de rendimiento de las imágenes.

En Angular 17, ampliamos el alcance de la guía sobre el rendimiento de las imágenes para incluir todas las apps de Angular. Ahora, si detectamos patrones de imagen que sabemos que afectan el rendimiento, como la carga diferida de una imagen LCP o la descarga de un archivo demasiado grande para la página, te lo informaremos, incluso si no usas NgOptimizedImage.

El rendimiento de las imágenes es importante para todas las apps, y nos entusiasma seguir creando protecciones para evitar errores comunes en las apps de Angular.

Proyecciones para el futuro

Ya estamos trabajando mucho en el desarrollo del próximo conjunto de funciones para NgOptimizedImage. Si bien el rendimiento de las imágenes sigue siendo nuestra preocupación principal, también nos gustaría agregar funciones que mejoren la experiencia de los desarrolladores para asegurarnos de que NgOptimizedImage siga siendo una opción atractiva para incluir imágenes en aplicaciones de Angular.

Una función que para nosotros es nuestra prioridad son los marcadores de posición de imágenes. Por lo general, se usan para que la carga de imágenes se vea mejor en aplicaciones web, pero pueden afectar el rendimiento si se implementan de forma incorrecta. Esperamos compilar en NgOptimizedImage un sistema de marcadores de posición de imagen que priorice el rendimiento. No te pierdas nuestro blog para conocer más anuncios.