en
· 3 min de leitura

Server Components mudam onde fica a fronteira

A fronteira antiga era a API. A nova é uma diretiva no topo do arquivo. A maioria dos times ainda não percebeu.

fullstacknextjsarchitecture

Por quinze anos a arquitetura de uma aplicação web teve uma fronteira óbvia: a API. O navegador de um lado, o servidor do outro, e JSON cruzando entre eles. Todo time desenhava essa linha do mesmo jeito porque a tecnologia obrigava.

React Server Components apagam essa linha e desenham uma nova. A maioria dos times que audito adotou as ferramentas novas sem perceber que a fronteira se moveu, e é daí que vêm os problemas.

A fronteira agora é uma diretiva

No App Router, todo componente é um Server Component a menos que o arquivo comece com 'use client'. Server Components rodam só no servidor. Podem ler o banco, ler o sistema de arquivos, usar segredos, e nada do código deles vai para o navegador. Client Components rodam nos dois lugares: primeiro no servidor para o render inicial, depois no navegador.

Então a fronteira arquitetural não é mais uma URL. É o ponto em que um Server Component renderiza um Client Component e passa props para ele. Tudo que cruza esse ponto precisa ser serializável. Funções não cruzam, exceto Server Actions, que são referências a código do servidor. Instâncias de classe não cruzam. Datas viram strings a menos que você trate isso.

Essa é uma fronteira real com regras reais, e merece o mesmo cuidado que você dava a um contrato de API. A diferença é que ninguém escreve spec para ela, porque parece só uma prop.

O que vai para o servidor

A consequência mais útil é que o data fetching sobe. Um componente de página faz await das queries diretamente. Server Components filhos também podem buscar seus próprios dados, e a memoização por requisição faz com que o mesmo fetch em três componentes vire uma única chamada de rede. Sem biblioteca de estado no cliente, sem coreografia de spinner, sem cascata de useEffect.

Também move o peso das dependências para o servidor. Um renderizador de markdown, uma biblioteca de formatação de datas, um syntax highlighter: se só um Server Component importa, o navegador nunca baixa. Já cortei bundles de cliente pela metade em auditorias apenas movendo imports para o outro lado da fronteira.

E move a autorização para o servidor por padrão. Se um componente que renderiza dados de admin é um Server Component, a checagem acontece onde não pode ser burlada editando JavaScript no navegador. Isso não é uma feature. É a remoção de uma classe inteira de vulnerabilidade.

As falhas que encontro

A primeira falha é a árvore de cliente acidental. Alguém adiciona 'use client' em um layout para um menu abrir e fechar, e agora todo componente abaixo daquele layout é um Client Component, incluindo os que deveriam buscar dados no servidor. A correção é composição: mantenha a parte interativa pequena e passe Server Components para dentro dela como children.

A segunda é vazamento. Um Server Component busca o registro completo do usuário e passa o objeto inteiro para um Client Component que só precisa do nome. O hash da senha agora está no payload do HTML. Verifico isso em toda auditoria, e encontro com mais frequência do que deveria. Passe os campos que precisa, nada mais, e use o import server-only em qualquer módulo que toque segredos.

A terceira é tratar uma Server Action como função privada. Ela é um endpoint POST que qualquer um pode chamar com qualquer payload. Valide a entrada, cheque a sessão dentro da action e nunca confie que um id vindo do cliente seja um que o usuário pode tocar.

Desenhando a linha de propósito

Minha regra: um componente vira Client Component quando precisa de um event handler, de estado do navegador ou de uma API do navegador. Nada mais merece a diretiva. A linha vai o mais baixo possível na árvore, e o que cruza é o dado mais fino que consigo.

A fronteira não desapareceu. Ela se moveu para um lugar mais fácil de cruzar e mais fácil de cruzar mal. Trate como a API que ela substituiu.