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 trabalhariam 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 explica como a nova diretiva de imagem, NgOptimizedImage, oferece suporte à otimização de imagens no Angular.

Contexto

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

Devido ao número e tamanho cada vez maiores, as imagens podem prejudicar o desempenho das páginas da Web e afetar as Core Web Vitals. Para 79,4% das páginas para computadores, uma imagem foi o elemento da Largest Contentful Paint (LCP) em 2021. A busca por imagens otimizadas tornou-se, portanto, um esforço constante para muitos de nós.

A equipe da Aurora acredita em aproveitar o poder das estruturas para fornecer soluções integradas para desafios comuns dos desenvolvedores. O primeiro trabalho deles na otimização de imagens foi o componente de imagem Next.js. Eles consideraram esse componente como um ponto de teste para saber se melhorar a experiência do desenvolvedor (DX) na otimização de imagens poderia melhorar o desempenho de mais apps que usam frameworks.

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

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

Oportunidade

O Angular é um dos principais frameworks de JavaScript usados por 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 do Angular no último ano.

Analisando as pontuações das Core Web Vitals, a porcentagem de origens do Angular que atendem a limites "bons" de LCP ainda precisa melhorar. Em junho de 2022, apenas 18,74% dos sites com Angular tiveram uma boa LCP em dispositivos móveis. Como as imagens são o elemento da LCP em mais de 70% das páginas da Web em dispositivos móveis e computadores, as imagens de LCP não otimizadas podem ser uma das principais causas de uma LCP mais insatisfatória em sites com 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 o Aurora criou até hoje e adapta o design à experiência de renderização do lado do cliente do Angular. Muitos dos problemas de otimização de imagens padrão foram resolvidos por:

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

Os destaques do design são os seguintes:

  1. Carregamento lento inteligente

    O ideal é que as imagens invisíveis para o usuário durante o carregamento da página (por exemplo, imagens abaixo da dobra ou de carrossel ocultas) tenham o carregamento lento. O carregamento lento libera os recursos do navegador para carregar outros textos, mídias ou scripts essenciais. A maioria das imagens não é crítica e precisa ser carregada lentamente, mas apenas 7,8% das páginas usaram esse recurso em 2021.

    A diretiva de imagem Angular carrega lentamente imagens não críticas por padrão e apenas carrega rapidamente imagens especialmente marcadas como priority. Isso garante que a maioria das imagens exiba o comportamento de carregamento ideal.

  2. Priorização de imagens críticas

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

    A diretiva de imagem age 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 da LCP foi marcada como priority conforme o esperado. Se não estiver marcado como priority, um erro será gerado, instruindo o desenvolvedor a adicionar o atributo priority à imagem LCP.

    Em última análise, essa combinação de automação e conformidade garante que a imagem da LCP tenha uma dica preconnect, um valor de atributo fetchpriority de high e não seja carregada lentamente.

  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 é compatível com uma API de carregador que permite definir o provedor de CDN e o URL de base na configuração. Depois de fazer a configuração, basta 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 de imagem fornece aos carregadores integrados a configuração ideal para as CDNs de imagem mais conhecidas. Esses carregadores formatarão os URLs de imagem automaticamente para garantir que o formato de imagem recomendado e as configurações de compactação 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 imagem. A diretiva de imagem executa as verificações a seguir.

    1. Imagens sem tamanho:a diretiva de imagem gera um erro se a marcação de imagem não tem largura e altura explícitas. Imagens sem tamanho podem causar mudanças de layout, afetando a métrica 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 é 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 incorretas (largura ou altura) 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 muito grandes:se a imagem não definir um srcset e a imagem intrínseca for significativamente maior que a renderizada, a diretiva exibirá 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. Descritores superiores a 2x geralmente não são recomendados, porque forçam dispositivos móveis de alta resolução a fazer o download de imagens muito grandes. Além disso, o olho humano não consegue distinguir muita diferença quando duas vezes mais.

Desafios

Adaptar as estratégias de otimização de imagens para funcionar com 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 no servidor (SSR, na sigla em inglês) ou a Geração de sites estáticos (SSG), enquanto no Angular é a renderização no lado do cliente (CSR, na sigla em inglês). Embora o Angular seja compatível com uma biblioteca SSR (angular/universal), a maioria dos apps com Angular (cerca de 60%) usa a 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 estabeleceu restrições adicionais, e a equipe teve que repensar como criar otimizações específicas para apps de CSR.

Estes são alguns dos desafios:

  1. Dicas de recursos de suporte

    O pré-carregamento de recursos essenciais ajuda o navegador a descobri-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 qualquer dica preload ao <head> significa que o recurso será pré-carregado para todas as rotas, mesmo quando ele 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 no cabeçalho do documento durante a renderização em um app da CSR não ajuda. Como a renderização ocorre após o download e a execução do JavaScript, o <head> será renderizado tarde demais para ter qualquer 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, o Aurora está trabalhando atualmente com a equipe da CLI do Angular para ativar a injeção automática de dicas de recursos no tempo de build. Não perca!

  2. Como otimizar o tamanho e o formato da imagem no servidor

    Como os apps do Angular normalmente 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 veiculadas como estão. Por isso, é 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 impõe 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 mostra a diferença que a diretiva de imagem Angular pode fazer no desempenho da imagem. Ela compara dois sites:

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

Site 2:use a diretiva de imagem em 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 no desempenho da diretiva de imagem em aplicativos Angular corporativos reais.

Um desses parceiros era a Land's End. Esperava-se que o site fosse um bom caso de teste para resultados que aplicativos reais podem ver.

Teste de laboratório do Lighthouse foi realizado no ambiente de controle de qualidade antes e depois do uso da 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, a LCP mediana diminuiu de 20,2 s para 12,0 s (40,6% de melhoria).

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, 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

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

  • Suporte para SSR do Angular

    A versão do MVP foi criada considerando as restrições de CSR do Angular, mas também será importante explorar soluções de otimização de imagens para 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 Angular vai estar disponível em etapas para os desenvolvedores, começando com a versão de prévia para desenvolvedores na v14.2.0. Teste o NgOptimizedImage e deixe seu feedback.

Um agradecimento especial a Katie Hempenius e Alex Castle pela contribuição deles.