Otimizar imagens com a diretiva de imagem angular

Kara erickson
Kara Erickson
Leena sohoni
Lena Sohoni

Em maio de 2022, as equipes do Aurora e do Angular anunciaram que vão 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. Nesta postagem, explicamos 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, em que 99,9% das páginas da Web geram solicitações de uma ou mais imagens. As imagens também são as principais influências no peso da página, representando uma média de 982 kilobytes por página.

Devido ao crescente número e tamanho, as imagens podem prejudicar o desempenho das páginas da Web e afetar as métricas das Core Web Vitals. Para 79,4% das páginas para computador, uma imagem foi o elemento de Maior exibição de conteúdo (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 dos frameworks para fornecer soluções integradas para desafios comuns de desenvolvedores. Seu primeiro trabalho no espaço de otimização de imagens foi o componente de imagem Next.js. Eles consideraram esse componente como um campo de teste para avaliar se a melhoria da experiência do desenvolvedor (DX) de otimização de imagens poderia levar a ganhos de desempenho para mais aplicativos que usam estruturas.

O primeiro conjunto de resultados do usuário do Next.js, Leboncoin, foi animador. A Leboncoin teve uma melhoria significativa na LCP (de 2,4s para 1,7s) depois que começou a usar o next/image. A adoção subsequente do next/image na comunidade influenciou o aumento das origens do Next.js que atingiram os limites da LCP. Logo houve solicitações para recursos semelhantes em outros frameworks, um deles sendo o Angular.

Por isso, a 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 os padrões de otimização de imagens no Angular.

Oportunidade

O Angular é um dos principais frameworks de JavaScript usados pelos desenvolvedores atualmente. Ele é usado por mais de 50 mil das origens rastreadas pelo HTTPArchive em dispositivos móveis e conta com quase 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 aos limites de LCP "bom" ainda precisa melhorar. Apenas 18,74% dos sites do Angular tinham uma boa LCP em dispositivos móveis em junho de 2022. 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 baixa em sites do Angular.

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

MVP para a diretiva NgOptimizedImage

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

  • Fornecer padrões fortes.
  • 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 não aparecem para o usuário no carregamento da página (por exemplo, imagens abaixo da dobra ou imagens de carrossel ocultas) precisam ser carregadas lentamente. O carregamento lento libera os recursos do navegador para carregar outros textos, mídias ou scripts essenciais. A maioria das imagens não é essencial e precisa ser carregada lentamente, mas apenas 7,8% das páginas usaram o carregamento lento nativo em 2021.

    Por padrão, a diretiva de imagem Angular carrega lentamente imagens não críticas e só carrega com atenção imagens especialmente marcadas como priority. 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 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 precisa 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 conforme o esperado. Se não estiver marcado como priority, um erro será gerado, instruindo o desenvolvedor a adicionar o atributo priority à imagem LCP.

    Por fim, 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 do 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 de desenvolvedor (DX) especialmente interessante para configurá-las no app. Ela é compatível com uma API de carregador que permite definir o provedor de CDN e seu URL base na sua 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 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 usadas. Esses carregadores formatarão URLs de imagens automaticamente para garantir que as configurações de compactação e o formato de imagem recomendados 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 seguiram as práticas recomendadas na marcação de imagem. A diretiva de imagem realiza as verificações a seguir.

    1. Imagens não dimensionadas:a diretiva de imagem vai gerar um erro se a marcação de imagem não tiver uma largura e altura explícitas. Imagens sem tamanho podem causar mudanças de layout, afetando a métrica Mudança de layout cumulativa (CLS, na sigla em inglês) 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 de width:height definida 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 erradas (largura ou altura) por engano ou
      2. Se você tiver definido uma dimensão por porcentagem no seu 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 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. Descritores superiores a 2x geralmente não são recomendados porque isso tem a consequência indesejada de forçar 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 muito acima de duas vezes.

Desafios

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

A diretiva de imagem é totalmente criada para que os CSR se alinhem ao caso de uso típico em aplicativos Angular. Isso gerou restrições adicionais, e a equipe teve que repensar a forma de criar otimizações específicas para apps de CSR.

Estes são alguns dos desafios encontrados:

  1. Dicas de recursos de suporte

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

    Adição manual: é difícil para os desenvolvedores adicionarem 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 seria pré-carregado para todas as rotas, mesmo quando não for necessário. Portanto, não é recomendável adicionar manualmente dicas preload.

    Adição automática durante a renderização:não ajuda no uso do framework para adicionar dicas de pré-carregamento ao cabeçalho do documento durante a renderização em um app CSR. Como a renderização ocorre depois do download e da 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 com a equipe da CLI do Angular para ativar a injeção automática de dicas de recursos no tempo de compilação. Não perca as novidades.

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

    Como os aplicativos 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 veiculadas 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 imponha o uso de CDNs de imagem, é altamente recomendável usá-la com a diretiva e seus carregadores integrados garantem que as opções de configuração corretas sejam utilizadas.

Impacto

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

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

Site 2:use a diretiva de imagem 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 um com tags de imagem nativas e o site dois com a diretiva de imagem Angular.

A equipe trabalhou com parceiros para validar o impacto no desempenho da diretiva de imagem em aplicativos reais do Angular corporativos.

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

Um 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 12s para 3s, uma melhoria de 75% na LCP. Em dispositivos móveis, a LCP mediana diminuiu de 20,2s para 12s (40,6% de melhoria).

Roteiro do futuro

Esta é apenas a primeira parte do design para a diretiva de imagem Angular. Há muitos outros recursos 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

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

  • Suporte para SSR do Angular

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

  • Melhorias na experiência do desenvolvedor

    NgOptimizedImage exige que os atributos width e height sejam especificados para cada imagem. No entanto, especificá-las para cada imagem pode ser cansativo para alguns desenvolvedores. Na próxima iteração, é possível melhorar a experiência do desenvolvedor, da seguinte maneira:

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

Conclusão

A diretiva de imagem Angular vai estar disponível para desenvolvedores em etapas, 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 ao Alex Castle pela contribuição.