Amo seu cache ❤️

Os usuários que carregarem o site pela segunda vez usarão o cache HTTP, portanto, verifique se ele funciona bem.

Esta postagem é um complemento do vídeo Love your cache, parte do conteúdo estendido da Conferência de Desenvolvedores do Chrome 2020. Confira o vídeo:

Quando os usuários carregam seu site pela segunda vez, o navegador usa os recursos dentro do cache HTTP dele para ajudar a tornar o carregamento mais rápido. Mas os padrões de armazenamento em cache na Web remontam a 1999 e são definidos amplamente. determinar se um arquivo, como CSS ou uma imagem, pode ser buscado novamente na rede em vez de carregado do seu cache é um pouco uma ciência imprecisa.

Nesta postagem, você vai conhecer um padrão prático e moderno de armazenamento em cache, que não faz nenhum armazenamento em cache. Mas esse é apenas o padrão e, obviamente, há mais nuances do que apenas "desativar". Boa leitura!

Objetivos

Quando um site é carregado pela segunda vez, você tem duas metas:

  1. Garanta que seus usuários tenham a versão mais atualizada disponível. Se você fez alguma alteração, ela será refletida rapidamente
  2. Faça o primeiro passo buscando o mínimo possível da rede

No sentido mais amplo, você só quer enviar a menor alteração aos seus clientes quando eles carregarem seu site novamente. Além disso, estruturar seu site para garantir a distribuição mais eficiente de qualquer mudança é um desafio (mais sobre isso abaixo e no vídeo).

Dito isso, você também tem outros botões ao considerar o armazenamento em cache. Talvez você tenha decidido permitir que o cache HTTP do navegador de um usuário mantenha seu site por um longo período para que nenhuma solicitação de rede seja necessária para atendê-lo. Ou você criou um service worker que atenderá a um site totalmente off-line antes de verificar se ele está atualizado. Essa é uma opção extrema, que é válida e é usada para muitas experiências da Web que priorizam apps off-line, mas a Web não precisa estar em um extremo somente de cache ou mesmo de apenas uma rede.

Contexto

Como desenvolvedores web, todos estamos acostumados com a ideia de ter um "cache desatualizado". Mas sabemos, quase instintivamente, as ferramentas disponíveis para resolver isso: fazer uma "atualização forçada", abrir uma janela anônima ou usar alguma combinação das ferramentas para desenvolvedores do seu navegador para limpar os dados de um site.

Os usuários regulares da Internet não têm o mesmo luxo. Nosso objetivo principal é garantir que os usuários tenham uma ótima experiência com o segundo carregamento, mas também é muito importante garantir que eles não enfrentem um momento ruim ou fiquem presos. Confira o vídeo se quiser me ouvir falar sobre como quase travamos o site web.dev/live.

Um motivo comum para o "cache desatualizado" é, na verdade, o padrão da era de 1999 para armazenamento em cache. Ele depende do cabeçalho Last-Modified:

Diagrama por quanto tempo recursos diferentes são armazenados em cache pelo navegador do usuário
Os recursos gerados em momentos diferentes (em cinza) são armazenados em cache por momentos diferentes. Assim, um segundo carregamento pode receber uma combinação de recursos armazenados em cache e novos

Cada arquivo carregado é mantido por mais 10% da vida útil atual dele, de acordo com o que é visto pelo navegador. Por exemplo, se index.html foi criado há um mês, ele será armazenado em cache pelo navegador por mais três dias.

Essa era uma ideia bem-intencionada na época, mas, devido à natureza fortemente integrada dos sites atuais, esse comportamento padrão significa que é possível chegar a um estado em que um usuário tem arquivos projetados para versões diferentes do seu site (por exemplo, o JS da versão de terça-feira e o CSS da versão de sexta-feira), tudo isso porque esses arquivos não foram atualizados exatamente ao mesmo tempo.

O caminho bem iluminado

Um padrão moderno para armazenamento em cache é não fazer nenhum armazenamento em cache e usar CDNs para aproximar seu conteúdo dos usuários. Sempre que um usuário carrega seu site, ele acessa a rede para verificar se ele está atualizado. Essa solicitação terá baixa latência, já que será fornecida por uma CDN geograficamente próxima de cada usuário final.

É possível configurar o host da Web para responder às solicitações da Web com este cabeçalho:

Cache-Control: max-age=0,must-revalidate,public

Basicamente, o arquivo é válido sem nenhum período de tempo, e você precisa validá-lo na rede antes de usá-lo novamente (caso contrário, será apenas "sugerido").

Esse processo de validação é relativamente barato em termos de bytes transferidos. Se um arquivo de imagem grande não for alterado, o navegador receberá uma pequena resposta 304, mas custa latência, porque um usuário ainda precisa ir à rede para descobrir. E essa é a principal desvantagem dessa abordagem. Isso pode funcionar muito bem para pessoas com conexões rápidas no 1o mundo, e onde sua CDN preferida tem uma ótima cobertura, mas não para aquelas que usam conexões móveis mais lentas ou usam uma infraestrutura ruim.

Independentemente disso, essa é uma abordagem moderna que é o padrão em um CDN conhecido, o Netlify, mas pode ser configurada em praticamente qualquer CDN. Para o Firebase Hosting, inclua esse cabeçalho na seção de hospedagem do arquivo firebase.json:

"headers": [
  // Be sure to put this last, to not override other headers
  {
    "source": "**",
    "headers": [ {
      "key": "Cache-Control",
      "value": "max-age=0,must-revalidate,public"
    }
  }
]

Então, embora eu ainda sugira isso como um padrão razoável, é apenas isso: o padrão. Continue lendo para saber como atualizar os padrões.

URLs com impressão digital

Ao incluir um hash do conteúdo do arquivo no nome de recursos, imagens e outros itens veiculados no seu site, você garante que esses arquivos sempre tenham conteúdo exclusivo. Isso resultará em arquivos chamados sitecode.af12de.js, por exemplo. Quando o servidor responder a solicitações para esses arquivos, você poderá instruir com segurança os navegadores do usuário final para armazená-los em cache por um longo período configurando-os com este cabeçalho:

Cache-Control: max-age=31536000,immutable

Esse valor é um ano, em segundos. De acordo com a especificação, esse valor é efetivamente igual a "sempre".

É importante ressaltar que você não precisa gerar esses hashes manualmente, já que dá muito trabalho manual. Você pode usar ferramentas como Webpack, Rollup e assim por diante. Leia mais sobre elas no Relatório de ferramentas.

Não se esqueça de que não é apenas o JavaScript que pode se beneficiar dos URLs com impressão digital. Recursos como ícones, CSS e outros arquivos de dados imutáveis também podem ser nomeados dessa maneira. Assista ao vídeo acima para saber um pouco mais sobre a divisão de código, que permite enviar menos código sempre que seu site mudar.

Independentemente de como seu site aborda o armazenamento em cache, esses tipos de arquivos com impressão digital são extremamente valiosos para qualquer site que você possa criar. A maioria dos sites simplesmente não muda a cada lançamento.

Obviamente, não podemos renomear nossas páginas "amigáveis" voltadas ao usuário dessa maneira: renomear seu arquivo index.html para index.abcd12.html. Isso é inviável, porque não é possível dizer aos usuários para acessar um novo URL sempre que carregarem seu site. Esses URLs "amigáveis" não podem ser renomeados e armazenados em cache dessa maneira, o que me leva a um possível meio termo.

Meio termo

Obviamente, existe espaço para um meio termo quando se trata de armazenamento em cache. Apresentamos duas opções extremas: cache nunca ou cache para sempre. Além disso, há vários arquivos que você pode querer armazenar em cache por um tempo, como os URLs "amigáveis" que mencionei acima.

Se você quiser armazenar esses URLs "amigáveis" em cache e o HTML deles, considere quais dependências eles incluem, como eles podem ser armazenados em cache e como o armazenamento em cache dos URLs por um período pode afetar você. Vejamos uma página HTML que inclui uma imagem como esta:

<img src="/images/foo.jpeg" loading="lazy" />

Se você atualizar ou mudar seu site excluindo ou mudando essa imagem de carregamento lento, os usuários que visualizarem uma versão em cache do HTML poderão receber uma imagem incorreta ou ausente, porque ainda armazenaram o /images/foo.jpeg original em cache quando acessarem o site novamente.

Se tomar cuidado, isso pode não afetá-lo. No entanto, é importante lembrar que o site, quando armazenado em cache pelos usuários finais, deixou de existir apenas nos servidores. Em vez disso, ele pode existir em partes dentro dos caches dos navegadores do usuário final.

Em geral, a maioria dos guias sobre armazenamento em cache falará sobre esse tipo de configuração. Você quer armazenar em cache por uma hora, várias horas e assim por diante? Para definir esse tipo de cache, use um cabeçalho como este, que armazena por 3.600 segundos ou uma hora:

Cache-Control: max-age=3600,immutable,public

Um último ponto. Se você estiver criando conteúdo oportuno que normalmente só pode ser acessado pelos usuários uma vez, como artigos de notícias, minha opinião é que eles nunca devem ser armazenados em cache e você deve usar nosso padrão razoável acima. Muitas vezes, superestimamos o valor do armazenamento em cache em vez do desejo de um usuário de sempre conferir o melhor e mais recente conteúdo, como uma atualização crítica de uma notícia ou um evento atual.

Opções não HTML

Além do HTML, algumas outras opções para arquivos que residem no meio termo incluem:

  • Procure recursos que não afetem outras pessoas

    • Por exemplo: evite CSS, já que ele causa mudanças na forma como o HTML é renderizado.
  • Imagens grandes que são usadas como parte de artigos oportunos

    • É provável que seus usuários não acessem um artigo mais do que algumas vezes. Por isso, não armazene em cache fotos ou imagens principais para sempre e desperdice espaço.
  • Um recurso que representa algo que, por si só, tem duração

    • Os dados JSON sobre o clima podem ser publicados apenas a cada hora. Assim, você pode armazenar em cache o resultado anterior por uma hora. Ele não muda na janela
    • Os builds de um projeto de código aberto podem ter limitação de taxa. Por isso, armazene em cache uma imagem de status do build até que seja possível que o status mude

Resumo

Quando os usuários carregam seu site pela segunda vez, você já recebeu um voto de confiança. Eles querem voltar e receber mais do que você oferece. Neste ponto, não se trata apenas de diminuir esse tempo de carregamento, e há várias opções disponíveis para garantir que o navegador faça apenas o trabalho necessário para fornecer uma experiência rápida e atualizada.

O armazenamento em cache não é um conceito novo na Web, mas talvez precise de um padrão razoável. Considere usar um e optar por melhores estratégias de armazenamento em cache quando precisar delas. Agradecemos por ler.

Veja também

Para um guia geral sobre o cache HTTP, consulte Evitar solicitações de rede desnecessárias com o cache HTTP.