[{"data":1,"prerenderedAt":16},["ShallowReactive",2],{"post-como-desenvolvi-o-novo-site-da-lab82-com-nextjs-e-claude-code":3},{"id":4,"imagem":5,"titulo":6,"slug":7,"tags":8,"date":13,"resumo":14,"artigo":15},9,"\u002Fimagens\u002Fblog\u002Ftiago-bernardes-como-desenvolvi-o-novo-site-da-lab82-com-nextjs-e-claude-code.webp","Como desenvolvi o novo site da Lab82 com Next.js e Claude Code","como-desenvolvi-o-novo-site-da-lab82-com-nextjs-e-claude-code",[9,10,11,12],"Next.js","React","Claude Code","Web Performance","31\u002F05\u002F2026","Desenvolvi sozinho o novo site institucional da Lab82 usando Next.js 16, React e TypeScript com deploy na Vercel. Neste post conto a arquitetura, a correção de um LCP invisível e os desafios da infraestrutura DNS.","\u003Cp>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.\u003C\u002Fp>\n\n\u003Ch3>Arquitetura\u003C\u002Fh3>\n\u003Cp>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.\u003C\u002Fp>\n\u003Cp>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.\u003C\u002Fp>\n\n\u003Ch3>O problema de performance que quase passou despercebido\u003C\u002Fh3>\n\u003Cp>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.\u003C\u002Fp>\n\u003Cp>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.\u003C\u002Fp>\n\u003Cp>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:\u003C\u002Fp>\n\u003Cpre>@keyframes hero-fade-up {\n  from { opacity: 0; transform: translateY(24px); }\n  to   { opacity: 1; transform: translateY(0); }\n}\u003C\u002Fpre>\n\u003Cp>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.\u003C\u002Fp>\n\u003Cp>A correção foi simples: remover o opacity: 0 do estado inicial, mantendo apenas o efeito de slide:\u003C\u002Fp>\n\u003Cpre>@keyframes hero-fade-up {\n  from { opacity: 1; transform: translateY(24px); }\n  to   { opacity: 1; transform: translateY(0); }\n}\u003C\u002Fpre>\n\u003Cp>Resultado imediato: o h1 passou a ser reconhecido como elemento LCP no primeiro frame.\u003C\u002Fp>\n\n\u003Ch3>Outras otimizações aplicadas\u003C\u002Fh3>\n\u003Cul>\n  \u003Cli>font-display: swap em todas as fontes para eliminar o FOIT (Flash of Invisible Text)\u003C\u002Fli>\n  \u003Cli>preload: true nas fontes do hero para antecipar o carregamento\u003C\u002Fli>\n  \u003Cli>Remoção do componente Reveal das seções acima da dobra, que atrasava a renderização do conteúdo visível\u003C\u002Fli>\n  \u003Cli>Configuração de browserslist moderno no package.json, eliminando a geração de polyfills desnecessários\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch3>Resultado final no PageSpeed Insights\u003C\u002Fh3>\n\u003Cul>\n  \u003Cli>\u003Cstrong>Performance:\u003C\u002Fstrong> Mobile 97 · Desktop 100\u003C\u002Fli>\n  \u003Cli>\u003Cstrong>LCP:\u003C\u002Fstrong> Mobile 2.5s · Desktop 0.5s\u003C\u002Fli>\n  \u003Cli>\u003Cstrong>TBT:\u003C\u002Fstrong> Mobile 60ms · Desktop 20ms\u003C\u002Fli>\n  \u003Cli>\u003Cstrong>CLS:\u003C\u002Fstrong> Mobile 0.003 · Desktop 0\u003C\u002Fli>\n  \u003Cli>\u003Cstrong>SEO:\u003C\u002Fstrong> Mobile 100 · Desktop 100\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch3>A infraestrutura DNS\u003C\u002Fh3>\n\u003Cp>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.\u003C\u002Fp>\n\u003Cp>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.\u003C\u002Fp>\n\u003Cp>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:\u003C\u002Fp>\n\u003Cpre>RewriteEngine On\nRewriteCond %{REQUEST_URI} ^\u002Fstaging [NC]\nRewriteRule ^ - [L]\nRewriteCond %{HTTP_HOST} ^lab82\\.dev$ [NC]\nRewriteRule ^(.*)$ https:\u002F\u002Fwww.lab82.dev\u002F$1 [R=301,L]\u003C\u002Fpre>\n\u003Cp>A exceção para \u002Fstaging garante que os projetos em desenvolvimento continuem acessíveis diretamente no servidor, sem serem redirecionados para a Vercel.\u003C\u002Fp>\n\n\u003Ch3>Stack utilizada\u003C\u002Fh3>\n\u003Cp>Next.js 16 · React · TypeScript · Tailwind CSS · Vercel · ISR · Claude Code (Anthropic) · Squarespace Domains · ValueHost · cPanel\u003C\u002Fp>",1780414804170]