Cache Busting, Chunk Load Error, Error Boundary e Versionamento de Assets
Explicarei a técnica de Cache Busting, mostrarei uma das causas do erro conhecido como Chunk Load Error, como identificar essa falha utilizando Error Boundary no React e, por fim, apresentarei uma possível solução utilizando versionamento de assets
O problema de cache em aplicações web
Ao trabalhar com websites, pode acontecer a seguinte situação: você publica uma nova versão do site, mas os usuários não recebem a atualização, mesmo após recarregarem a página
Uma possível causa está relacionada às políticas de cache configuradas pelo servidor de hospedagem de conteúdo estático, como o GitHub Pages. Normalmente:
-
Arquivos HTML recebem headers HTTP com políticas de cache de curta duração, sendo baixados novamente ao recarregar a página
-
Arquivos JavaScript e CSS recebem headers com cache de longa duração, fazendo com que o navegador os recupere do cache local em vez de baixá-los novamente
Em aplicações CSR (Client-Side Rendering), o HTML geralmente é leve, então a ausência de cache não é um problema significativo. Porém, para arquivos JavaScript e CSS, o cache melhora bastante o tempo de carregamento
Exemplo prático
Foi criado um repositório chamado "example" e configurado o GitHub Pages. Inicialmente, foram adicionados dois arquivos: um index.html e um script.js
Ao acessar o site e analisar a aba Network no Chrome DevTools, é possível observar que tanto o index.html quanto o script.js foram baixados. Ao recarregar a página, o index.html é baixado novamente, mas o script.js é servido a partir do cache
Em seguida, os textos de ambos os arquivos são alterados para "Version 2" e as mudanças são publicadas
Após recarregar a página:
-
O conteúdo renderizado diretamente pelo HTML é atualizado
-
O conteúdo inserido via JavaScript permanece com a versão antiga, mesmo após vários reloads
Isso ocorre porque o navegador continua utilizando o script.js em cache
Cache Busting
Uma forma simples de resolver esse problema é alterar o nome do arquivo JavaScript, forçando o navegador a baixá-lo novamente. Por exemplo:
-
Renomear
script.jsparascript-v3.js -
Atualizar a referência no
index.html
Como a referência mudou, o navegador entende que se trata de um novo recurso e faz o download novamente, aplicando corretamente as alterações. Essa técnica é conhecida como Cache Busting
React, Vite e geração automática de hash
Ferramentas modernas como o Vite já aplicam cache busting automaticamente. Ao criar um projeto React com Vite e executar o comando de build, o Vite:
-
Gera arquivos com hash no nome (ex:
index-abc123.js) -
Mantém o
index.htmlsem hash -
Atualiza automaticamente o
index.htmlpara apontar para os arquivos finais com hash -
Coloca tudo dentro da pasta dist
Se o código-fonte for alterado e o build for executado novamente, novos hashes serão gerados. Isso força o navegador a baixar a nova versão dos arquivos
Code Splitting, Lazy Loading e Chunks
Ao adicionar React Router à aplicação e criar duas rotas, inicialmente o Vite continua gerando apenas um único arquivo JavaScript
Com o crescimento do projeto, esse arquivo pode ficar muito grande, prejudicando o tempo de carregamento inicial
Uma solução é utilizar React.lazy para carregar as rotas sob demanda (lazy loading). Assim:
-
O arquivo principal (por exemplo,
index.js) é carregado inicialmente -
Os arquivos relacionados a cada rota são baixados apenas quando a rota é acessada.
Esses arquivos adicionais são chamados de chunks. Então, após o build teremos:
-
Um arquivo principal
-
Um arquivo para cada rota (por exemplo,
Home.jseSomePage.js)
Ao acessar a página inicial, apenas o arquivo principal e o chunk da Home são baixados. O chunk da SomePage só é baixado ao navegar para essa rota
O problema: Chunk Load Error
Agora imagine o seguinte cenário:
-
Um usuário acessa o site e baixa apenas o arquivo principal e o chunk da Home
-
Você publica uma nova versão do site
-
Os arquivos antigos são removidos do servidor
-
Os novos arquivos possuem hashes diferentes
O usuário, com a versão antiga do arquivo principal em cache, tenta navegar para /somePage. O arquivo principal antigo ainda referencia o chunk antigo (por exemplo, SomePage-DOXVUgsz.js)
O navegador faz uma requisição para esse arquivo, mas ele não existe mais no servidor. Resultado: sua aplicação quebra
Detectando erros com Error Boundary
É possível capturar erros como o Chunk Load Error utilizando Error Boundary no React
O Error Boundary funciona como um "try-catch" para componentes React. Ele captura erros durante a fase de renderização e permite exibir uma interface de fallback
Exemplo:
import React from "react";
export default class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
// Você pode enviar o erro para o backend aqui
console.error("Error caught:", error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div>
<h1>Algo deu errado.</h1>
<p>{this.state.error?.message}</p>
</div>
);
}
return this.props.children;
}
}
O Error Boundary pode envolver toda a aplicação ou apenas partes específicas, como cada rota individualmente
Com monitoramento adequado, é possível identificar picos de erro logo após a publicação de novas versões
Recomenda-se implementar esse mecanismo antes de aplicar qualquer correção estrutural
Estratégias para corrigir o Chunk Load Error
Após identificar o problema em produção, existem duas abordagens principais:
1. Forçar o usuário a recarregar a página
Ao detectar o erro, exibir uma mensagem solicitando que o usuário atualize a página. Mas pode causar perda de dados, especialmente em formulários grandes sem auto-save
2. Manter arquivos de versões antigas no servidor
Ao publicar uma nova versã não remover imediatamente os arquivos antigos, permitindo que clientes com versões antigas ainda consigam baixar os chunks correspondentes
Essa abordagem evita o erro, mas pode gerar inconsistências caso o backend também tenha sido atualizado
Versionamento de assets por pasta
Vou seguir aqui com a segunda abordagem. Podemos modificar o processo de build do Vite para que, em vez de colocar os arquivos em assets/, eles sejam colocados em uma pasta com identificador de versão, como:
-
/v1/... -
/v2/...
O index.html deve ser único e sempre apontar para a versão mais recente
Assim:
-
Usuários com arquivos antigos ainda conseguem acessar os chunks antigos
-
Ao recarregar a página, baixam o novo
index.html. Consequentemente, passam a utilizar a versão mais recente
Limitações
O Vite só altera o hash quando necessário. Por exemplo, se o CSS não mudou entre v1 e v2, o hash será o mesmo
Se os arquivos estiverem em pastas diferentes (v1 e v2), o navegador baixará novamente o CSS porque o caminho completo mudou, mesmo que o conteúdo seja idêntico
Como alternativa, é possível manter todos os arquivos de todas as versões na mesma pasta. Assim arquivos não alterados continuam sendo servidos do cache. Porém, com o crescimento do projeto, o espaço ocupado pode aumentar significativamente e será necessário criar uma estratégia para remover versões antigas
Na abordagem por pasta versionada, é simples remover versões antigas após alguns dias (por exemplo, deletando a pasta v1). Já na abordagem com todos os arquivos misturados em uma única pasta, é mais difícil identificar quais arquivos pertencem a versões antigas e quais ainda são utilizados pela versão atual
Publicação orignal com imagens de exemplo: Medium
