Como Reduzimos Respostas Lentas em 80%

A Subito é um dos principais marketplaces da Itália. Lidamos com milhares de requisições a cada minuto. Nossa página de detalhes do anúncio é vital para o SEO e para a receita.

Migramos esta página do Next.js Pages Router para o App Router. Não interrompemos o desenvolvimento de novos produtos para realizar isso. Avançamos em pequenos passos.

Aqui está como fizemos.

A Abordagem

Utilizamos uma estratégia incremental. Adicionamos a árvore do App Router ao lado do antigo Pages Router. Isso nos permitiu lançar novos recursos enquanto realizávamos a migração.

Utilizamos Server Components para gerenciar o data fetching. Isso removeu a necessidade de passar dados por muitas camadas. Também criamos uma Data Access Layer. Isso garantiu que buscássemos os dados apenas uma vez por requisição.

Utilizamos Suspense e o hook use() para habilitar o HTML streaming. Isso exibe um skeleton screen enquanto os dados são carregados. O usuário visualiza a página mais rápido.

Os Desafios

Problema 1: HTTP 410 Gone Mecanismos de busca precisam de um status 410 quando uma página é removida permanentemente. O App Router não possui uma forma nativa de enviar isso. Resolvemos isso usando nosso servidor Express. O servidor intercepta a resposta e altera o código de status.

Problema 2: HTML Streaming Descobrimos que nossos skeleton screens de carregamento não apareciam. A página ficava em branco por segundos.

Descobrimos que o Nginx e o Akamai estavam fazendo o buffering de nossas respostas. Se o CDN faz o buffer do HTML, o streaming falha. Tivemos que desativar o buffering no Nginx e aplicar configurações personalizadas no Akamai. Assim que corrigimos isso, o conteúdo foi transmitido perfeitamente para o usuário.

O Rollout

Realizamos o rollout em duas fases para proteger nosso SEO.

Fase 1: Movemos o tráfego para o App Router, mas mantivemos o streaming desativado. Fizemos isso uma categoria por vez.

Fase 2: Habilitamos o HTML streaming. Testamos isso primeiro em categorias pequenas. Nossa equipe de SEO monitorou os rankings por duas semanas antes de passarmos para a próxima categoria.

Os Resultados

Os resultados foram enormes. Antes da migração, até 40% de nossas respostas eram lentas. Após a migração, as respostas lentas caíram 80%.

A maioria das páginas agora carrega em menos de 500ms.

Principais Aprendizados

Como reduzimos respostas lentas em 80% migrando para o Next.js App Router

A transição do Pages Router para o App Router foi uma das decisões mais impactantes que tomamos para melhorar a performance da nossa aplicação. Neste artigo, vou compartilhar como essa mudança nos permitiu reduzir o tempo de resposta em 80%.

O Problema: O peso do Pages Router

Com o Pages Router, enfrentávamos um desafio comum em aplicações React de grande escala: o tamanho do bundle de JavaScript.

Cada vez que um usuário acessava uma página, o navegador precisava baixar, processar e executar uma quantidade significativa de JavaScript para realizar a hidratação (hydration) da página. Isso resultava em:

A Solução: Next.js App Router

Ao migrar para o App Router, pudemos tirar proveito de três pilares fundamentais: Server Components, Streaming e um novo modelo de Caching.

1. Server Components

A maior mudança foi a adoção de Server Components. Diferente dos componentes tradicionais, os Server Components são renderizados inteiramente no servidor.

Isso significa que o JavaScript necessário para renderizar esses componentes não é enviado para o cliente. O resultado é um bundle muito menor e uma página que carrega quase instantaneamente.

// Exemplo de um Server Component buscando dados
async function UserProfile({ userId }) {
  const res = await fetch(`https://api.example.com/user/${userId}`);
  const user = await res.json();

  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.bio}</p>
    </div>
  );
}

2. Streaming e Suspense

Com o App Router, não precisamos mais esperar que toda a página seja gerada no servidor para começar a enviá-la ao cliente. Usando Streaming com o componente Suspense do React (ou o arquivo loading.js do Next.js), podemos enviar partes da interface conforme elas ficam prontas.

Isso melhora drasticamente a percepção de velocidade do usuário. Enquanto os dados pesados são buscados, o usuário já consegue interagir com o restante da página.

3. Caching Inteligente

O novo modelo de cache do Next.js é muito mais granular. Ele nos permite cachear requisições de dados de forma automática e eficiente, reduzindo a carga no nosso backend e acelerando as respostas.

Conclusão

A migração para o App Router não foi apenas uma atualização de versão; foi uma mudança de paradigma na forma como pensamos a arquitetura da nossa aplicação. Ao mover a lógica de busca de dados e a renderização para o servidor, conseguimos uma experiência de usuário muito mais fluida e rápida.

Os resultados foram claros: uma redução de 80% no tempo de resposta e uma melhora significativa em todas as métricas de performance.