Next.js, React, Claude Code, Web Performance

Como desenvolvi o novo site da Lab82 com Next.js e Claude Code

31/05/2026

Como desenvolvi o novo site da Lab82 com Next.js e Claude Code

Recentemente coloquei no ar o novo site institucional da Lab82 Agência Digital, empresa com mais de 20 anos de mercado e mais de 300 projetos entregues. Desenvolvi o projeto inteiro sozinho, utilizando o Claude Code como assistente de IA durante todo o ciclo de desenvolvimento.

Arquitetura

O site foi construído com Next.js 16 usando App Router, com separação criteriosa entre Server Components e Client Components. O output é estático com ISR (Incremental Static Regeneration) para revalidação automática dos dados do portfólio, que são consumidos de uma API externa com revalidação a cada hora.

O hero da página utiliza um canvas animado via WebGL. Para não comprometer o SSR, o componente foi isolado em um Client Component com dynamic import e ssr:false, garantindo que o JavaScript do canvas só carregue no cliente e fora do caminho crítico de renderização.

O problema de performance que quase passou despercebido

Durante os testes com PageSpeed Insights, o relatório retornou "NO LCP", ou seja, o browser não conseguia identificar nenhum elemento candidato ao Largest Contentful Paint.

O h1 do hero estava presente no HTML do servidor, as fontes estavam configuradas corretamente e o canvas já havia sido movido para Client Component. Mesmo assim, nada.

Após investigação, a causa foi encontrada no CSS global: a classe hero-left, ancestral direto do h1, usava uma animação com a seguinte keyframe:

@keyframes hero-fade-up {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: translateY(0); }
}

Com animation-fill-mode: both e animation-delay de 0.35s, o ancestral do h1 ficava com opacity: 0 no primeiro frame. O browser interpretava o elemento como invisível e não o registrava como LCP.

A correção foi simples: remover o opacity: 0 do estado inicial, mantendo apenas o efeito de slide:

@keyframes hero-fade-up {
  from { opacity: 1; transform: translateY(24px); }
  to   { opacity: 1; transform: translateY(0); }
}

Resultado imediato: o h1 passou a ser reconhecido como elemento LCP no primeiro frame.

Outras otimizações aplicadas

  • font-display: swap em todas as fontes para eliminar o FOIT (Flash of Invisible Text)
  • preload: true nas fontes do hero para antecipar o carregamento
  • Remoção do componente Reveal das seções acima da dobra, que atrasava a renderização do conteúdo visível
  • Configuração de browserslist moderno no package.json, eliminando a geração de polyfills desnecessários

Resultado final no PageSpeed Insights

  • Performance: Mobile 97 · Desktop 100
  • LCP: Mobile 2.5s · Desktop 0.5s
  • TBT: Mobile 60ms · Desktop 20ms
  • CLS: Mobile 0.003 · Desktop 0
  • SEO: Mobile 100 · Desktop 100

A infraestrutura DNS

A configuração de infraestrutura foi um dos pontos mais complexos do projeto. O domínio lab82.dev está registrado no Squarespace (ex-Google Domains), mas a zona DNS autoritativa está na ValueHost, onde roda a revenda de hospedagem com cPanel, e-mail corporativo e outros sites.

O desafio: colocar o site na Vercel sem derrubar o cPanel (acessado via lab82.dev:2083), o webmail e os demais serviços que dependem do mesmo domínio.

A solução foi manter o registro A do apex apontando para a ValueHost e servir o site da Vercel exclusivamente pelo subdomínio www, via CNAME. O redirect de lab82.dev para www.lab82.dev foi resolvido com um .htaccess na public_html:

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/staging [NC]
RewriteRule ^ - [L]
RewriteCond %{HTTP_HOST} ^lab82\.dev$ [NC]
RewriteRule ^(.*)$ https://www.lab82.dev/$1 [R=301,L]

A exceção para /staging garante que os projetos em desenvolvimento continuem acessíveis diretamente no servidor, sem serem redirecionados para a Vercel.

Stack utilizada

Next.js 16 · React · TypeScript · Tailwind CSS · Vercel · ISR · Claude Code (Anthropic) · Squarespace Domains · ValueHost · cPanel