Otimizando Core Web Vitals com Next.js 15

 


Parece familiar?

Mas primeiro…

Antes de avançar, é importante fazer uma breve revisão e lembrar a razão de todo esse esforço. As métricas de Core Web Vitals são cruciais para a otimização de mecanismos de busca e para a satisfação geral do usuário em qualquer página.

Com React Server Components, streaming e várias otimizações embutidas que funcionam sem a necessidade de manipular o Webpack, é possível alcançar pontuações verdes no Lighthouse sem muitas noites em claro depurando tamanhos de bundles.

Compreender essas funcionalidades é fundamental para o bom funcionamento dos projetos.

Estratégia de Renderização Correta

O desempenho da página começa com a forma como ela é renderizada, e a equipe de desenvolvimento não deseja causar uma impressão negativa.

  1. Static Site Generation (SSG): Isso é útil para conteúdo que não muda muito, como posts de blog, landing pages e documentação. A aplicação é pré-construída uma vez e servida rapidamente para sempre.

  2. Incremental Static Regeneration (ISR): O ponto ideal para muitas aplicações. Permite servir páginas em cache instantaneamente, mas atualizá-las em segundo plano quando necessário, aprimorando ainda mais o desempenho estático com dados dinâmicos. Perfeito para páginas de produtos de e-commerce ou artigos de notícias.

  3. Server-Side Rendering (SSR): Recomenda-se usar esta estratégia apenas quando for absolutamente necessário ter dados atualizados a cada requisição, como em painéis de análise ou conteúdo específico do usuário que não pode ser armazenado em cache.

  4. Client-Side Rendering (CSR): Honestamente, esta deve ser a estratégia menos prioritária ou até evitada. A menos que haja uma razão muito específica, o CSR prejudica os Core Web Vitals mais do que ajuda, pois compila o JavaScript no lado do cliente.

Otimização de Imagens: O Ponto de Partida Mais Fácil

Um segredo mal guardado é que a imagem principal de uma página é provavelmente o elemento LCP, e otimizá-la é frequentemente a maneira mais rápida de melhorar o desempenho.

import Image from 'next/image';

<Image
  src="/hero-image.jpg"
  alt="Hero image"
  width={1200}
  height={600}
  priority
  sizes="(max-width: 768px) 100vw, 1200px"
/>

Corrigir Mudanças de Layout com Otimização de Fontes

import { Inter } from 'next/font/google';

export const inter = Inter({ 
  subsets: ['latin'], 
  display: 'swap'
});

export default function RootLayout({ children }) {
  return (
    <html className={inter.className}>
      <body>{children}</body>
    </html>
  );
}

Ilhas de Interatividade: Enviar Menos JavaScript

'use client';

import { useTransition } from 'react';
import { useDiscount } from '../hooks';

export function CartCheckout({ id }: { id: string }) {
  const [pending, start] = useTransition();

   return (
    <button 
      disabled={pending} 
      onClick={() => start(() => applyDiscount(id))}
    >
      {pending ? 'Applying...' : 'Apply discount'}
    </button>
  );
}

Divisão de Bundles e Envio Apenas do Necessário

import dynamic from 'next/dynamic';

// Only load when needed
const HeavyChart = dynamic(() => import('../components/HeavyChart'), {
  loading: () => <div>Loading chart...</div>,
  ssr: false // Skip ssr for client components
});

// Route-based splitting happens automatically, but you can also do:
const AdminPanel = dynamic(() => import('../components/AdminPanel'));

export default function Dashboard() {
  const [showChart, setShowChart] = useState(false);

  return (
    <div>
      <h1>Dashboard</h1>
      <button onClick={() => setShowChart(true)}>
        Show Analytics
      </button>

      {showChart && <HeavyChart />}
    </div>
  );
}

É também possível usar o pacote next/bundle-analyzer para visualizar o que está realmente contido nos bundles:

npm install @next/bundle-analyzer
// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
});

module.exports = withBundleAnalyzer({
  // rest of config
});

Otimizando para INP

Além de enviar menos JavaScript, estas são as ações que realmente importam para tornar as interações mais rápidas e responsivas:

  • Manter os event handlers leves: A lógica pesada deve ser movida para fora dos click handlers. Ninguém deseja esperar 500ms para um botão responder.

  • Usar startTransition: É recomendado envolver as atualizações não urgentes em useTransition para que não bloqueiem a UI e a renderização crítica.

  • Virtualizar listas longas: Se a aplicação estiver renderizando centenas de itens, é útil usar algo como react-virtual para renderizar apenas os itens visíveis em uma lista.

Caching para Dados Antigos e Lentos

// Per-fetch caching in Server Components
const data = await fetch('/api/products', {
  next: { revalidate: 120 } // Cache for 2 minutes
});

// Per-route caching
export const revalidate = 60; // ISR every minute
export const dynamic = 'force-dynamic'; // Always SSR

Streaming com Suspense

import { Suspense } from 'react';

export default function ProductPage() {
  return (
    <div>
      <h1>Product Details</h1>

      <div className="product-info">
        <h2>Amazing Widget</h2>
        <p>This is the best widget ever made.</p>
      </div>

      <Suspense fallback={<div>Loading reviews...</div>}>
        <ProductReviews />
      </Suspense>

      <Suspense fallback={<div>Loading recommendations...</div>}>
        <RelatedProducts />
      </Suspense>
    </div>
  );
}

A shell da página acima carrega instantaneamente, então as avaliações e recomendações são transmitidas à medida que ficam prontas. Os usuários veem o progresso em vez de uma tela em branco.

Algumas Ferramentas Úteis

Algumas ferramentas que podem realmente ajudar a equipe a depurar, medir e ajustar as páginas da web para obter a pontuação métrica perfeita incluem:

  1. Chrome Lighthouse: Embutido nas DevTools.

  2. PageSpeed Insights: https://pagespeed.web.dev/


Pontuações perfeitas de Core Web Vitals não são tudo. No entanto, elas servem como um bom indicativo para medir e determinar se uma aplicação é realmente agradável de usar.

Agora, é a vez da comunidade tech: Qual tem sido o maior desafio de desempenho? Imagens massivas, JavaScript pesado ou algo completamente diferente?

Portfólio: trillionclues.vercel.app

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *