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 JavaScript usados pelos desenvolvedores atualmente. Ele é usado por mais de 50 mil das origens rastreadas pelo HTTPArchive em dispositivos móveis e tem quase 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 lenta em sites do Angular.

O diretivo de imagem do Angular foi criado para ajudar a melhorar esses números.

MVP para a diretiva NgOptimizedImage

O MVP do diretivo 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 importantes

    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 os 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 precisa fazer o download da imagem com alta prioridade.
    • No modo de desenvolvimento, uma verificação de execução confirma que uma dica de recurso preconnect foi incluída de acordo com a 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 fornecem serviços de otimização por padrão.

    A diretiva incentiva o uso de CDNs de imagem, oferecendo uma experiência de desenvolvedor (DX) especialmente atraente para a configuração delas no app. Ela oferece suporte a uma API de loader que permite definir o provedor de CDN e o 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 tags de imagem a seguir e reduz a marcação que os desenvolvedores precisam incluir em 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 é especificar os atributos width e height nas imagens.

    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 no 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 é totalmente criada para que o 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.

Alguns dos desafios encontrados são os seguintes:

  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: é difícil para os desenvolvedores adicionar a sugestão 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 todas as rotas (pelo menos no momento da veiculação). Adicionar qualquer sugestão preload ao <head> significa que o recurso será carregado previamente para 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.

    Na primeira versão da diretiva, uma combinação de dicas preconnect e fetchpriority serve para priorizar a imagem em vez de um 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 imagens 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 os loaders integrados garantem 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. Ele 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 do 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. Esperava-se que o site fosse um bom caso de teste para resultados que aplicativos reais poderiam ter.

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

Roteiro futuro

Este é apenas o primeiro artigo sobre o design da diretiva de imagem do Angular. Há muitos outros recursos planejados para versões futuras, incluindo:

  • Melhor suporte a 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 integrar 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 isso para cada imagem pode ser cansativo para alguns desenvolvedores. Há uma possibilidade de melhorar a experiência do desenvolvedor na próxima iteração da seguinte maneira:

    1. Suporte a um modo adicional (semelhante à opção de layout de imagem "fill" no Next.js) que não exige que a largura/altura seja definida de forma explícita.
    2. Usar a integração da CLI para definir automaticamente a largura e a altura de imagens locais determinando as dimensões reais da imagem.

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.