Otimizar imagens com a diretiva de imagem angular

Kara Erickson
Kara Erickson
Leena Sohoni
Leena Sohoni

Em maio de 2022, as equipes do Aurora e do Angular anunciaram que iriam colaborar em uma diretiva de imagem para o Angular. A diretiva foi lançada recentemente para a prévia para desenvolvedores como parte do Angular v14.2. Esta postagem fala sobre como a nova diretiva de imagem, NgOptimizedImage, oferece suporte à otimização de imagens no Angular.

Contexto

As imagens são um componente comum e crucial da experiência do usuário na Web, com 99,9% das páginas da Web gerando solicitações para uma ou mais imagens. As imagens também são os elementos que mais contribuem para o peso da página, constituindo uma média de 982 kilobytes por página.

Devido ao número e tamanho crescentes, as imagens podem prejudicar o desempenho das páginas da Web e afetar as métricas das Principais métricas da Web. Para 79,4% das páginas para computador, uma imagem foi o elemento da maior exibição de conteúdo (LCP) em 2021. A busca por imagens otimizadas se tornou uma tarefa constante para muitos de nós.

A equipe do Aurora acredita na capacidade de aproveitar os frameworks para oferecer soluções integradas para desafios comuns de desenvolvedores. A primeira incursão deles no espaço de otimização de imagens foi o componente de imagem do Next.js. Eles consideraram esse componente como um campo de testes para saber se a melhoria da experiência do desenvolvedor (DX) da otimização de imagens poderia levar a ganhos de desempenho para mais apps que usam frameworks.

O primeiro conjunto de resultados do usuário Leboncoin do Next.js foi encorajador. A Leboncoin notou uma melhora significativa na LCP (de 2,4 para 1,7 segundos) depois de começar a usar next/image. A adoção subsequente de next/image na comunidade contribuiu para o aumento das origens do Next.js que atendem aos limites de LCP. Logo surgiram solicitações de recursos semelhantes em outros frameworks, um deles sendo o Angular.

Como resultado, a Aurora consultou o Angular e o Nuxt para criar protótipos de componentes de imagem para esses frameworks. O componente de imagem do Nuxt foi lançado no ano passado. Agora, a diretiva de imagem do Angular (NgOptimizedImage) foi lançada para trazer os padrões de otimização de imagem para o Angular.

Oportunidade

O Angular é um dos principais frameworks de JavaScript usados pelos desenvolvedores atualmente. Ele é usado por mais de 50 mil origens rastreadas pelo HTTPArchive em dispositivos móveis e tem cerca de 3 milhões de downloads semanais no NPM.

LCP para sites Angular nos últimos 12 meses.

Analisando as pontuações das Core Web Vitals, a porcentagem de origens do Angular que atendem aos limites de LCP "bons" ainda precisa de trabalho. Apenas 18,74% dos sites do Angular tiveram um bom LCP em dispositivos móveis em junho de 2022. Como as imagens são o elemento LCP de mais de 70% das páginas da Web em dispositivos móveis e computadores, imagens LCP não otimizadas podem ser uma das principais causas de uma LCP mais baixa em sites do Angular.

A diretiva de imagem Angular foi criada para ajudar a melhorar esses números.

MVP para a diretiva NgOptimizedImage

O MVP da diretiva de imagem do Angular se baseia nas lições dos componentes de imagem que a Aurora criou até o momento, adaptando o design à experiência de renderização do lado do cliente do Angular. Muitos dos problemas padrão de otimização de imagens foram resolvidos por:

  • Fornecer padrões fortes.
  • Gerar erros ou avisos para garantir a conformidade com as práticas recomendadas.

Os destaques do design são os seguintes:

  1. Carregamento lento inteligente

    As imagens que são invisíveis para o usuário no carregamento da página (por exemplo, imagens abaixo da dobra ou imagens ocultas do carrossel) devem ser carregadas de forma lenta. O carregamento lento libera recursos do navegador para carregar outros textos, mídias ou scripts essenciais. A maioria das imagens não é essencial e precisa ser carregada de forma lenta, mas apenas 7,8% das páginas usaram o carregamento lento nativo em 2021.

    O diretivo de imagem do Angular carrega imagens não críticas de forma lenta por padrão e só carrega imagens marcadas especialmente como priority de forma imediata. Isso garante que a maioria das imagens apresente um comportamento de carregamento ideal.

  2. Priorização de imagens críticas

    Adicionar dicas de recursos (por exemplo, preload ou preconnect) para priorizar o carregamento de imagens importantes é uma prática recomendada. No entanto, a maioria dos apps não as usa. De acordo com o Almanaque da Web de 2021, apenas 12,7% das páginas para dispositivos móveis usam dicas de pré-conexão e apenas 22,1% das páginas para dispositivos móveis usam dicas de pré-carregamento.

    O diretivo de imagem atua em duas frentes quando as imagens são marcadas como prioridade.

    • Ele define a fetchpriority da imagem como "high" para que o navegador saiba que deve fazer o download da imagem com alta prioridade.
    • No modo de desenvolvimento, uma verificação de ambiente de execução confirma que uma dica de recurso preconnect foi incluída correspondente à origem da imagem.

    No modo de desenvolvimento, a diretiva também usa a API PerformanceObserver para verificar se a imagem LCP foi marcada como priority como esperado. Se não estiver marcado como priority, um erro será gerado, instruindo o desenvolvedor a adicionar o atributo priority à imagem do LCP.

    Essa combinação de automação e conformidade garante que a imagem do LCP tenha uma sugestão preconnect, um valor de atributo fetchpriority de high e não seja carregada com atraso.

  3. Configuração otimizada para ferramentas de imagem conhecidas

    É recomendável que os aplicativos Angular usem CDNs de imagem, que geralmente oferecem serviços de otimização por padrão.

    A diretiva incentiva o uso de CDNs de imagem, oferecendo uma experiência do desenvolvedor (DX) especialmente atraente para configurá-las no app. Ela oferece suporte a uma API de carregador que permite definir o provedor de CDN e seu URL base na configuração. Depois de configurado, você só precisa definir o nome do recurso na marcação. Por exemplo,

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

    Isso equivale a incluir as seguintes tags de imagem e reduz a marcação que os desenvolvedores precisam incluir para cada imagem.

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

    A diretiva "image" oferece carregador integrados com a configuração ideal para os CDNs de imagem mais conhecidos. Esses carregadores formatam URLs de imagem automaticamente para garantir que o formato de imagem e as configurações de compactação recomendadas sejam usados para cada CDN.

  4. Erros e avisos integrados

    Além das otimizações integradas acima, a diretiva também tem verificações integradas para garantir que os desenvolvedores tenham seguido as práticas recomendadas na marcação de imagens. A diretiva de imagem executa as seguintes verificações.

    1. Imagens sem tamanho:a diretiva de imagem gera um erro se a marcação de imagem não tiver definido uma largura e uma altura explícitas. Imagens sem tamanho podem causar mudanças de layout, afetando a métrica de Cumulative Layout Shift (CLS) da página. A prática recomendada para evitar isso é que as imagens precisam ter os atributos width e height especificados.

    2. Proporção:a diretiva de imagem gera um erro para informar aos desenvolvedores se a proporção do width:height definido no HTML não está próxima da proporção real da imagem renderizada. Isso pode fazer com que a imagem pareça distorcida na tela. Isso pode acontecer se

      1. Você definiu as dimensões (largura ou altura) erradas por engano ou
      2. Se você tiver definido uma dimensão por porcentagem no CSS, mas não a outra (por exemplo, width: 100% precisa de height: auto para garantir que a imagem cresça nas duas dimensões).
    3. Imagens de tamanho inadequado:se a imagem não definir um srcset e a imagem intrínseca for significativamente maior que a imagem renderizada, a diretiva vai mostrar um aviso sugerindo o uso dos atributos srcset e sizes.

    4. Densidade da imagem:a diretiva vai gerar um erro se você tentar incluir uma imagem na srcset com uma densidade de pixels maior que 3x. Descrições maiores que 2x geralmente não são recomendadas porque forçam dispositivos móveis de alta resolução a fazer o download de imagens enormes. Além disso, o olho humano não consegue perceber uma diferença acima de 2x.

Desafios

Adaptar as estratégias de otimização de imagens para funcionar em uma estrutura do lado do cliente foi um dos principais desafios ao projetar NgOptimizedImage. A experiência de renderização padrão no Next.js é a renderização do lado do servidor (SSR) ou a geração de sites estáticos (SSG), enquanto no Angular é a renderização do lado do cliente (CSR). Embora o Angular ofereça suporte a uma biblioteca SSR, angular/universal, a maioria dos apps do Angular (cerca de 60%) usa CSR.

A diretiva de imagem foi criada inteiramente para que a CSR se alinhe ao caso de uso típico em apps do Angular. Isso definiu outras restrições, e a equipe teve que repensar como criar otimizações específicas para apps de RSE.

Estes são alguns dos desafios:

  1. Dicas de recursos de suporte

    O pré-carregamento de recursos essenciais ajuda o navegador a detectá-los mais cedo. No entanto, incluir dicas de recursos em apps do Angular é complicado porque:

    Adição manual: os desenvolvedores têm dificuldade para adicionar a dica de recurso preload manualmente. O Angular usa um arquivo index.html compartilhado para todo o projeto ou para todas as rotas no site. Assim, o <head> do documento é o mesmo para todos os trajetos, pelo menos no momento da exibição. Adicionar uma sugestão preload ao <head> significa que o recurso será carregado previamente em todas as rotas, mesmo quando não for necessário. Portanto, a adição manual de dicas preload não é recomendada.

    Adição automática durante a renderização:usar o framework para adicionar dicas de pré-carregamento ao cabeçalho do documento durante a renderização em um app CSR não ajuda. Como a renderização ocorre depois que o JavaScript é feito o download e executado, o <head> será renderizado tarde demais para ter algum valor.

    Para a primeira versão da diretiva, uma combinação de dicas preconnect e fetchpriority serve para priorizar a imagem em vez de uma preload. No entanto, a Aurora está trabalhando com a equipe do Angular CLI para ativar a injeção automática de dicas de recursos no momento da criação. Fique ligado!

  2. Otimizar o tamanho e o formato da imagem no servidor

    Como os apps do Angular geralmente são renderizados no lado do cliente, as imagens no sistema de arquivos não podem ser compactadas no momento da solicitação e são exibidas como estão. Por esse motivo, é recomendável usar CDNs de imagem para compactar imagens e convertê-las em formatos modernos, como WebP ou AVIF, sob demanda.

    Embora a diretiva não exija o uso de CDNs de imagem, é altamente recomendável usá-las com a diretiva e seus carregadores integrados para que as opções de configuração corretas sejam usadas.

Impacto

A demonstração a seguir demonstra a diferença que a diretiva de imagem do Angular pode fazer na performance da imagem. Ele compara dois sites:

Site 1:usa elementos <img> nativos com imagens veiculadas pelo CDN do Imgix (com opções de configuração padrão).

Site 2:use a diretiva "image" para todas as imagens. Ela também inclui as otimizações recomendadas diretamente por avisos ou erros gerados pela diretiva.

Comparação de tira de filme: o site 1 com tags de imagem nativas e o site 2 com a diretiva de imagem Angular.

A equipe trabalhou com parceiros para validar o impacto da performance da diretiva de imagem em aplicativos empresariais reais do Angular.

Um deles foi a Land's End. A expectativa era que o site fosse um bom caso de teste para resultados que aplicativos reais podem ver.

O teste de laboratório do Lighthouse foi realizado no ambiente de controle de qualidade antes e depois de usar a diretiva de imagem. Em computadores, a LCP média diminuiu de 12,0s para 3,0s, uma melhoria de 75% na LCP. Em dispositivos móveis, o LCP médio diminuiu de 20,2 para 12,0 segundos (melhoria de 40,6%).

Roteiro futuro

Esta é apenas a primeira parte do design da diretiva de imagem do Angular. Muitos outros recursos estão planejados para versões futuras, incluindo:

  • Suporte aprimorado para imagens responsivas:

    No momento, o NgOptimizedImage oferece suporte ao uso de srcset, mas os atributos srcset e sizes precisam ser fornecidos manualmente para cada imagem. No futuro, a diretiva poderá gerar os atributos srcset e sizes automaticamente.

  • Injeção automática de dicas de recursos

    Talvez seja possível fazer a integração com o Angular CLI para gerar tags de pré-conexão e pré-carregamento para imagens LCP críticas.

  • Suporte ao SSR do Angular

    A versão do MVP foi projetada considerando as restrições de CSR do Angular, mas também será importante explorar soluções de otimização de imagens para o SSR do Angular (angular/universal).

  • Melhorias na experiência do desenvolvedor

    NgOptimizedImage exige que os atributos width e height sejam especificados para cada imagem. No entanto, especificar esses valores para cada imagem pode ser cansativo para alguns desenvolvedores. É possível melhorar a experiência do desenvolvedor aqui na próxima iteração da seguinte maneira:

    1. Ofereça suporte a um modo adicional (semelhante à opção de layout de imagem no Next.js "fill") que não exija a definição de largura/altura explícita.
    2. Usar a integração com a CLI para definir automaticamente a largura e a altura de imagens locais determinando as dimensões reais das imagens.

Conclusão

A diretiva de imagem do Angular vai estar disponível para os desenvolvedores em etapas, começando pela versão de pré-lançamento para desenvolvedores na v14.2.0. Teste o NgOptimizedImage e deixe seu feedback.

Agradecemos especialmente a Katie Hempenius e Alex Castle pela contribuição.