Core Web Vitals são um problema de arquitetura
Você não conserta LCP com plugin. As métricas estão medindo seu fluxo de dados, suas fronteiras e seu deploy.
Quando um time me pede ajuda com Core Web Vitals, espera um engenheiro de performance. Recebe um arquiteto. As notas são sintoma, e a doença é quase sempre estrutural: de onde vêm os dados, onde fica a fronteira entre servidor e cliente, e o que a página tem permissão de fazer antes de saber o que está mostrando.
Três métricas importam. Largest Contentful Paint, quanto tempo até o conteúdo principal ficar visível. Interaction to Next Paint, quanto tempo a página leva para responder quando o usuário faz algo. Cumulative Layout Shift, quanto a página pula. Cada uma mapeia para uma decisão de arquitetura.
LCP é uma decisão de fluxo de dados
O maior elemento na maioria das páginas é uma imagem de destaque, um título ou um card de produto. Ele não pode pintar até o servidor ter os dados para renderizá-lo, e o servidor não tem os dados até a query mais lenta do caminho crítico retornar.
Então a pergunta não é como otimizar a imagem. É por que a imagem está esperando uma query que não tem nada a ver com ela. Com Server Components e Suspense, a casca da página e o destaque podem renderizar imediatamente enquanto o painel de recomendações chega por streaming depois. Isso é uma escolha arquitetural sobre o que é crítico, feita por página, e move o LCP mais do que qualquer formato de imagem jamais vai mover.
O segundo assassino de LCP é a cascata de requisições. Um layout busca o usuário, depois a página busca a conta, depois um componente busca o plano, cada um esperando o anterior. Inicie toda busca independente no topo e aguarde todas juntas. A cascata é um problema de estrutura de código, e aparece em segundos.
Depois as partes chatas que ainda são arquitetura: a imagem é servida com dimensões explícitas e dica de prioridade, as fontes são hospedadas localmente e pré-carregadas, o CDN está de fato cacheando os assets estáticos e o HTML tem um Cache-Control sensato. Eu checo os headers antes de checar o código.
INP é uma decisão de fronteira
Interaction to Next Paint fica ruim quando a main thread está ocupada. A main thread fica ocupada quando há JavaScript demais, e há JavaScript demais quando a fronteira entre servidor e cliente foi desenhada alta demais. Um layout marcado com 'use client' para abrir um menu arrasta a subárvore inteira para o bundle, e cada um desses componentes hidrata antes de a página conseguir responder a um clique.
A correção é mover a fronteira para baixo. Ilhas interativas, pequenas e específicas, com Server Components ao redor. Scripts de terceiros são o outro culpado: um widget de chat, uma tag de analytics e um banner de consentimento podem consumir cada um mais tempo de main thread do que a aplicação inteira. Carregue depois da interação, ou nem carregue, e meça cada um sozinho antes de decidir.
Tarefas longas dentro de event handlers são a última peça. Se um clique dispara uma computação síncrona sobre dez mil linhas, nenhum framework vai te salvar. Mova o trabalho para o servidor, um worker ou uma transition, e pinte primeiro.
CLS é uma decisão de contrato
Layout shift acontece quando a página não sabe o tamanho que algo vai ter. Uma imagem sem dimensões. Um banner injetado depois do carregamento. Uma fonte que troca para uma métrica diferente. Cada um é o navegador sendo obrigado a adivinhar.
A resposta arquitetural é que todo elemento assíncrono reserva seu espaço antes de chegar. Skeletons com as dimensões finais. Aspect ratio em mídia. Fontes de fallback com métricas ajustadas. Um Suspense boundary cujo fallback tem a mesma altura do conteúdo. Isso é um contrato entre o servidor e o layout, e é desenhado, não ajustado.
Meça no campo, não no laboratório
Notas de laboratório de um desktop com fibra são mentira. Os usuários que falham nos limites estão em um celular intermediário em uma rede congestionada, e só o monitoramento de usuários reais mostra isso. Embarque a biblioteca de web vitals, envie os números para o seu próprio backend com o nome da rota anexado, e olhe o percentil 75 por rota, porque é sobre ele que os limites são definidos.
Quando fizer isso, vai encontrar o que eu encontro em auditorias: a rota lenta é lenta por causa de uma decisão que alguém tomou sobre dados, não sobre pixels. Conserte a decisão, e a nota vem junto.