De 6,3 MB a 0,37 MB: anatomia de um site 10 vezes mais rápido

De 6,3 MB a 0,37 MB: anatomia de um site 10 vezes mais rápido — ilustração de capa

Este é um estudo de caso que podemos publicar com uma confiança incomum, porque o paciente foi este próprio site. Em uma sessão de trabalho, levamos nossa página inicial de um payload de 6,3 MB e um Largest Contentful Paint mobile de 34,6 segundos para 0,37 MB e 3,6 segundos — e a acessibilidade de 76 para 100. Aqui está exatamente o que estava errado, o que mudamos e o que medimos. Sem prints de sites alheios; números nossos.

A linha de base (era ruim)

Métrica (mobile)AntesDepois
Score de Performance5076 (89 no desktop)
Largest Contentful Paint34,6 s3,6 s
Cumulative Layout Shift0,2590
Acessibilidade84100
Best Practices96100
Peso da home6,3 MB0,37 MB

Os números pós-correção são de laboratório (Lighthouse, 4G simulado) contra o build de produção servido localmente; os números de campo em produção vão variar.

Achado #1: uma imagem era 82% da página

O fundo do hero era um PNG de 5,14 MB e 2816 pixels. Duas páginas irmãs carregavam PNGs próprios de 9,4 MB e 6,8 MB — 21,5 MB de imagens de hero em três páginas. A correção é sem graça e vale mais do que todas as outras otimizações juntas: redimensionar para a maior largura renderizada (1920px) e converter para WebP. Resultado: 5,14 MB → 191 KB, visualmente indistinguível sob o overlay escuro do hero. Como a imagem era um background CSS — invisível ao preload scanner do navegador até o CSS ser parseado — adicionamos <link rel="preload" as="image" fetchpriority="high">.

Achado #2: o servidor mandava tudo cru, sempre

O servidor web não tinha compressão nem cache headers: 550 KB de CSS/JS viajavam sem compressão a cada visita. Ativar o gzip cortou o payload de texto em ~75% (nossa maior folha de estilos foi de 89 KB para 14,5 KB no fio), e os cache headers tornaram as visitas recorrentes quase gratuitas. Um alerta que vale roubar: nossas regras de cache por regex teriam capturado em silêncio rotas que precisam ser proxeadas para outro serviço — prefixar esses location com ^~ os protege. Encontramos isso em teste, não em produção, que é o único lugar aceitável para encontrar.

Achado #3: morte por mil bloqueios de renderização

Uma fonte de ícones inteira carregada para exatamente um glifo (substituída por um SVG inline). Vinte variantes de webfonts declaradas, seis usadas. Três scripts parseados de forma síncrona antes do primeiro paint (agora defer). Um loader decorativo de tela cheia que segurava a página por 900 ms depois de tudo já ter carregado. E um widget residual do template que pedia um arquivo removido do build — um 404 garantido e erro de console em cada carregamento de cada página, que sozinho custava quatro pontos de Best Practices.

Achado #4: o layout shift se esconde nas boas intenções

Nossa maior lição de CLS: adicionar atributos width/height a uma imagem usando as dimensões intrínsecas piorou as coisas, porque o CSS limitava a altura renderizada — o header reservava 165px, colapsava para 40px e empurrava tudo abaixo. Os atributos devem descrever a geometria renderizada. O CLS foi de 0,259 a zero.

O que deliberadamente não fizemos

Nenhuma migração de framework, nenhum build pipeline, nenhum tree-shaking do bundle legado. Disciplina importa: 90% do ganho veio de imagens, compressão e headers — mudanças com risco de regressão quase nulo. Os pontos mobile restantes vivem em trabalho de critical-CSS cujo risco/benefício é uma decisão separada e consciente.

Pontos-chave

  • Pese sua página antes de otimizar qualquer coisa: um único asset era 82% da nossa.
  • gzip + cache headers são uma mudança de 30 minutos com retorno permanente.
  • Atributos width/height devem corresponder à geometria renderizada, não à intrínseca.
  • Medir, mudar, medir de novo — e publicar seus números.

Trabalha em um setor regulado e luta com os problemas descritos aqui? Construímos software exatamente para isso.

Fale com a PBS