spinny:~/writing $ vim nextjs-16-cache-components.md
1~2Durante anos, uma das perguntas mais irritantes no Next.js foi: “Esta página é estática ou dinâmica?”. Parece uma pergunta simples, até você adicionar uma chamada para `cookies()`, um `fetch` com opções diferentes, um cliente de banco de dados, um CMS, um carrinho de compras ou um conteúdo personalizado.3~4Next.js 16 é interessante porque tenta tornar essa conversa menos misteriosa. Isso não elimina a complexidade, mas muda o modelo mental: as rotas são dinâmicas por padrão, o cache se declara onde necessário e `Suspense` se torna a maneira natural de compor shells rápidos com partes que permanecem atualizadas.5~6O recurso a ser entendido são os componentes de cache. Stable Turbopack, React Compiler, `proxy.ts` e as novas APIs de invalidação são importantes, mas giram em torno do mesmo problema: construir aplicativos rápidos sem ter que adivinhar o que a estrutura decidiu nos bastidores.7~8## Porque essa coisa importa9~10Em um aplicativo real você não tem apenas “páginas estáticas” e “páginas dinâmicas”. Você tem peças diferentes com necessidades diferentes.11~12A ficha do produto pode mudar algumas vezes ao dia. O preço pode mudar com mais frequência. A disponibilidade deve estar quase ativa. O nome de usuário é pessoal. As avaliações podem ser transmitidas. A barra lateral pode ser estável. O carrinho não.13~14Se você tratar tudo como uma unidade, sempre terminará em um de dois extremos:15~16- cache agressivo e risco de ver dados antigos;17- renderização dinâmica em todos os lugares e desempenho pior que o necessário.18~19Cache Components serve justamente para evitar essa falsa escolha.20~21## O modelo na prática22~23Com `cacheComponents: true`, você pode declarar o que pode ser armazenado em cache usando `"use cache"`. Então você pode associar duração e tags a `cacheLife()` e `cacheTag()`. As partes dinâmicas permanecem dinâmicas e podem ser isoladas com `Suspense`.24~25```mermaid26flowchart TD27 Request[Solicitação do usuário] --> Shell[Shell em cache]28 Request --> Dynamic[Seções dinâmicas]29 Shell --> FirstPaint[Primeiro conteúdo rápido]30 Dynamic --> Stream[Streaming dentro do Suspense]31 Stream --> Complete[Página inteira]32```33~34A configuração é pequena:35~36```typescript37// next.config.ts38import type { NextConfig } from 'next';39~40const nextConfig: NextConfig = {41 cacheComponents: true,42};43~44export default nextConfig;45```46~47A grande mudança não está na configuração. É como você começa a escrever os componentes.48~49```tsx50// app/products/[slug]/page.tsx51import { Suspense } from 'react';52import { cacheLife, cacheTag } from 'next/cache';53~54async function getProduct(slug: string) {55 'use cache';56~57 cacheLife('hours');58 cacheTag(`product:${slug}`);59~60 return db.product.findUnique({ where: { slug } });61}62~63async function ProductDetails({ slug }: { slug: string }) {64 const product = await getProduct(slug);65~66 return (67 <section>68 <h1>{product.name}</h1>69 <p>{product.description}</p>70 </section>71 );72}73~74async function LiveInventory({ slug }: { slug: string }) {75 const inventory = await db.inventory.findFirst({ where: { slug } });76 return <p>{inventory.quantity} pezzi disponibili</p>;77}78~79export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) {80 const { slug } = await params;81~82 return (83 <>84 <ProductDetails slug={slug} />85 <Suspense fallback={<p>Controllo disponibilità...</p>}>86 <LiveInventory slug={slug} />87 </Suspense>88 </>89 );90}91```92~93A página não precisa estar toda armazenada em cache ou totalmente dinâmica. A ficha do produto pode ser rápida e reutilizável. O estoque pode permanecer atualizado. O usuário vê algo imediatamente, sem esperar pela parte mais lenta.94~95## `use cache` é documentação executável96~97O que eu gosto em `"use cache"` é que ele força você a deixar uma intenção explícita. Ao ler uma função, você imediatamente entende que alguém decidiu: “esses dados podem ser reutilizados”.98~99É especialmente útil quando você não está usando `fetch`. Muitos aplicativos leem dados do Prisma, Drizzle, SDKs internos, clientes CMS ou funções de serviço. Nesses casos o antigo raciocínio baseado apenas nas opções `fetch` não era suficiente.100~101Uma regra prática:102~103- conteúdo de cachea relativamente estável;104- use tags granulares;105- deixa permissões dinâmicas, sessões, carrinhos, notificações e estados transacionais;106- coloque partes lentas dentro de `Suspense`;107- medir antes de dizer "melhoramos o desempenho".108~109## Invalidar sem jogar tudo fora110~111O cache só será útil se você puder atualizá-lo com precisão. Aqui `cacheTag`, `revalidateTag` e `updateTag` tornam-se importantes.112~113Exemplo:114~115```typescript116'use server';117~118import { updateTag } from 'next/cache';119~120export async function updateProductName(productId: string, name: string) {121 await db.product.update({122 where: { id: productId },123 data: { name },124 });125~126 updateTag(`product:${productId}`);127}128```129~130O detalhe importante é a tag. `product:${productId}` informa um limite preciso. `products` conta um balde enorme. A princípio, o enorme balde é confortável; depois de alguns meses, esse é o motivo pelo qual você invalida metade de um aplicativo para alterar um título.131~132## Stable Turbopack: a parte que você ouve todos os dias133~134Next.js 16 traz o Turbopack para o centro de desenvolvimento e construção. Não é o recurso mais poético, mas é o que você sente enquanto trabalha: servidor que inicia mais cedo, atualização mais rápida, compilações que deixam de parecer uma pausa forçada para o café.135~136Dito isso, eu não migraria uma base de código cheia de plug-ins personalizados de olhos fechados. Eu verificaria:137~138- construção local;139- importação fora do padrão;140- MDX, SVG e CSS;141- Plug-ins do Webpack restantes;142- páginas críticas;143- diferenças nos tempos de construção.144~145Para novos projetos, eu começaria pelo padrão. Para os mais maduros, eu faria uma migração comedida.146~147## Compilador React: remova o ruído, não o pensamento148~149React Compiler 1.0 é estável e Next.js 16 oferece suporte com `reactCompiler`. A promessa é reduzir muita memorização manual: menos `memo`, menos `useMemo`, menos `useCallback` usado "por segurança".150~151```typescript152// next.config.ts153import type { NextConfig } from 'next';154~155const nextConfig: NextConfig = {156 reactCompiler: true,157};158~159export default nextConfig;160```161~162Eu não trataria isso como um pó mágico. O compilador ajuda quando o código segue bem as regras do React. Se os componentes tiverem efeitos colaterais estranhos, mutações ocultas ou ganchos mal utilizados, isso precisa ser corrigido primeiro.163~164A maneira saudável de experimentar:165~1661. atualizar `eslint-plugin-react-hooks`;1672. corrigir violações reais;1683. habilite-o em uma área controlada;1694. medir o tempo de construção e o comportamento;1705. remova a memorização manual somente quando ela não for mais necessária.171~172O objetivo não é apagar todos os `useMemo`. O objetivo é parar de escrever memoizações preventivas porque temos medo de renderizar.173~174## `proxy.ts` e o limite da rede175~176O antigo `middleware.ts` torna-se `proxy.ts`. É uma mudança de nome, mas faz sentido: esse arquivo fica no limite da solicitação, não é um middleware genérico tradicional no estilo back-end.177~178```typescript179// proxy.ts180import { NextRequest, NextResponse } from 'next/server';181~182export default function proxy(request: NextRequest) {183 const isLoggedIn = Boolean(request.cookies.get('session'));184~185 if (!isLoggedIn && request.nextUrl.pathname.startsWith('/dashboard')) {186 return NextResponse.redirect(new URL('/login', request.url));187 }188~189 return NextResponse.next();190}191```192~193A regra aqui é simples: mantenha o tamanho pequeno. Redirecionamento, roteamento de autenticação, cabeçalhos, reescritas essenciais. Se começar a parecer um segundo back-end, provavelmente está fazendo muito.194~195## Como eu realmente migraria196~197Eu não ativaria todos os recursos de uma vez. Eu faria isso:198~1991. Eu atualizo Next, React e React DOM;2002. Eu lanço o codemod oficial;2013. Corrijo alterações importantes em `params`, `searchParams`, `cookies()`, `headers()` e `draftMode()`;2024. Eu migro `middleware.ts` para `proxy.ts`;2035. Verifico compilações e páginas críticas;2046. Eu habilito os componentes de cache em uma seção onde o cache atualmente cria atrito;2057. Defino convenções para tags e invalidação;2068. Eu tento o React Compiler separadamente;2079. comparação de métricas antes e depois.208~209A boa migração não é aquela que utiliza todos os novos recursos. É o que torna o comportamento do aplicativo mais legível.210~211## O que muda na forma de pensar212~213A coisa mais útil sobre Next.js 16 é que ele força você a nomear melhor as intenções. Uma função não é apenas “obter o produto do banco de dados”. É "pegue o produto, posso armazená-lo em cache por horas, invalido-o com esta tag". Um componente não é apenas “renderizar a página”. É “este é o shell rápido, esta peça é pessoal, isso vem em streaming”.214~215A princípio parece mais trabalho. Então se torna uma forma de calma. As decisões de desempenho não estão mais escondidas em uma combinação de padrões, heurísticas e memória tribal. Eles estão no código.216~217## Fontes úteis218~219- [Notas de versão do Next.js 16](https://nextjs.org/blog/next-16)220- [Componentes de cache - documentos Next.js](https://nextjs.org/docs/app/getting-started/cache-components)221- [usar cache - documentos Next.js](https://nextjs.org/docs/app/api-reference/directives/use-cache)222- [Compilador React v1.0](https://react.dev/blog/2025/10/07/react-compiler-1)223~
NORMAL · nextjs-16-cache-components.md [readonly]223 lines · :q to close