spinny:~/writing $ less nextjs-16-cache-components.md
12Durante años una de las preguntas más molestas en Next.js ha sido: "¿Esta página es estática o dinámica?". Parece una pregunta simple, hasta que agregas una llamada a `cookies()`, un `fetch` con diferentes opciones, un cliente de base de datos, un CMS, un carrito de compras o un contenido personalizado.34Next.js 16 es interesante porque intenta hacer que esta conversación sea menos misteriosa. No elimina la complejidad, pero cambia el modelo mental: las rutas son dinámicas de forma predeterminada, el caché se declara cuando es necesario y `Suspense` se convierte en la forma natural de componer shells rápidos con partes que se mantienen actualizadas.56La característica que hay que entender son los componentes de caché. Stable Turbopack, React Compiler, `proxy.ts` y las nuevas API de invalidación son importantes, pero giran en torno al mismo problema: crear aplicaciones rápidas sin tener que adivinar qué decidió el marco detrás de escena.78## Porque esto importa910En una aplicación real no sólo hay "páginas estáticas" y "páginas dinámicas". Tienes diferentes piezas con diferentes necesidades.1112La ficha del producto puede cambiar algunas veces al día. El precio puede cambiar más a menudo. La disponibilidad debe ser casi activa. El nombre de usuario es personal. Las reseñas se pueden transmitir. La barra lateral puede ser estable. El carro no.1314Si tratas todo como una unidad, siempre terminas en uno de dos extremos:1516- almacenamiento en caché agresivo y riesgo de ver datos antiguos;17- renderizado dinámico en todas partes y rendimiento peor de lo necesario.1819Cache Components sirve precisamente para evitar esta falsa elección.2021## El modelo en la práctica.2223Con `cacheComponents: true`, puedes declarar qué se puede almacenar en caché usando `"use cache"`. Luego puede asociar la duración y las etiquetas con `cacheLife()` y `cacheTag()`. Las partes dinámicas siguen siendo dinámicas y se pueden aislar con `Suspense`.2425```mermaid26flowchart TD27 Request[Solicitud de usuario] --> Shell[shell en caché]28 Request --> Dynamic[Secciones dinámicas]29 Shell --> FirstPaint[Primer contenido rápido]30 Dynamic --> Stream[Streaming dentro del suspenso]31 Stream --> Complete[Página completa]32```3334La configuración es pequeña:3536```typescript37// next.config.ts38import type { NextConfig } from 'next';3940const nextConfig: NextConfig = {41 cacheComponents: true,42};4344export default nextConfig;45```4647El gran cambio no está en la configuración. Está en cómo empiezas a escribir los componentes.4849```tsx50// app/products/[slug]/page.tsx51import { Suspense } from 'react';52import { cacheLife, cacheTag } from 'next/cache';5354async function getProduct(slug: string) {55 'use cache';5657 cacheLife('hours');58 cacheTag(`product:${slug}`);5960 return db.product.findUnique({ where: { slug } });61}6263async function ProductDetails({ slug }: { slug: string }) {64 const product = await getProduct(slug);6566 return (67 <section>68 <h1>{product.name}</h1>69 <p>{product.description}</p>70 </section>71 );72}7374async function LiveInventory({ slug }: { slug: string }) {75 const inventory = await db.inventory.findFirst({ where: { slug } });76 return <p>{inventory.quantity} pezzi disponibili</p>;77}7879export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) {80 const { slug } = await params;8182 return (83 <>84 <ProductDetails slug={slug} />85 <Suspense fallback={<p>Controllo disponibilità...</p>}>86 <LiveInventory slug={slug} />87 </Suspense>88 </>89 );90}91```9293No es necesario que la página esté toda en caché o dinámica. La ficha de producto puede ser rápida y reutilizable. El inventario puede mantenerse actualizado. El usuario ve algo de inmediato, sin esperar la parte más lenta.9495## `use cache` es documentación ejecutable9697Lo que me gusta de `"use cache"` es que te obliga a hacer explícita una intención. Cuando lees una función, comprendes inmediatamente que alguien ha decidido: "estos datos se pueden reutilizar".9899Es especialmente útil cuando no estás usando `fetch`. Muchas aplicaciones leen datos de Prisma, Drizzle, SDK internos, clientes CMS o funciones de servicio. En esos casos, el antiguo razonamiento basado únicamente en las opciones `fetch` no era suficiente.100101Una regla general:102103- contenido de caché relativamente estable;104- utilizar etiquetas granulares;105- deja permisos dinámicos, sesiones, carritos, notificaciones y estados transaccionales;106- poner partes lentas dentro de `Suspense`;107- medir antes de decir "mejoramos el rendimiento".108109## Invalidar sin tirarlo todo110111El caché sólo es útil si puedes actualizarlo con precisión. Aquí `cacheTag`, `revalidateTag` y `updateTag` se vuelven importantes.112113Ejemplo:114115```typescript116'use server';117118import { updateTag } from 'next/cache';119120export async function updateProductName(productId: string, name: string) {121 await db.product.update({122 where: { id: productId },123 data: { name },124 });125126 updateTag(`product:${productId}`);127}128```129130El detalle importante es la etiqueta. `product:${productId}` indica un límite preciso. `products` dice un cubo enorme. Al principio el enorme cubo resulta cómodo; después de unos meses se convierte en el motivo por el que invalidas media aplicación para cambiar un título.131132## Turbopack estable: la parte que escuchas todos los días133134Next.js 16 lleva Turbopack al centro de desarrollo y construcción. No es la característica más poética, pero es la que sientes mientras trabajas: servidor que se inicia antes, actualización más rápida, compilaciones que dejan de parecer una pausa para el café forzada.135136Dicho esto, no migraría una base de código llena de complementos personalizados con los ojos cerrados. Yo comprobaría:137138- construcción local;139- importación no estándar;140- MDX, SVG y CSS;141- Quedan complementos de paquete web;142- páginas críticas;143- diferencias en los tiempos de construcción.144145Para proyectos nuevos, comenzaría desde el valor predeterminado. Para los maduros, haría una migración medida.146147## React Compiler: elimina el ruido, no el pensamiento148149React Compiler 1.0 es estable y Next.js 16 lo admite con `reactCompiler`. La promesa es reducir mucha memorización manual: menos `memo`, menos `useMemo`, menos `useCallback` utilizados "por seguridad".150151```typescript152// next.config.ts153import type { NextConfig } from 'next';154155const nextConfig: NextConfig = {156 reactCompiler: true,157};158159export default nextConfig;160```161162No lo trataría como un polvo mágico. El compilador ayuda cuando el código sigue bien las reglas de React. Si los componentes tienen efectos secundarios extraños, mutaciones ocultas o ganchos mal utilizados, eso debe solucionarse primero.163164La forma saludable de probarlo:1651661. actualizar `eslint-plugin-react-hooks`;1672. corregir violaciones reales;1683. habilitarlo en un área controlada;1694. medir el tiempo de construcción y el comportamiento;1705. elimine la memorización manual sólo cuando ya no sea necesaria.171172El objetivo no es borrar todos los `useMemo`. El objetivo es dejar de escribir memorización preventiva porque tenemos miedo de renderizar.173174## `proxy.ts` y el límite de la red175176El antiguo `middleware.ts` se convierte en `proxy.ts`. Es un cambio de nombre, pero tiene sentido: ese archivo se encuentra en el límite de la solicitud, no es un middleware genérico tradicional de estilo backend.177178```typescript179// proxy.ts180import { NextRequest, NextResponse } from 'next/server';181182export default function proxy(request: NextRequest) {183 const isLoggedIn = Boolean(request.cookies.get('session'));184185 if (!isLoggedIn && request.nextUrl.pathname.startsWith('/dashboard')) {186 return NextResponse.redirect(new URL('/login', request.url));187 }188189 return NextResponse.next();190}191```192193La regla aquí es simple: mantenlo pequeño. Redirección, enrutamiento de autenticación, encabezados, reescrituras esenciales. Si empieza a parecer un segundo backend, probablemente esté haciendo demasiado.194195## Cómo realmente migraría196197No activaría todas las funciones a la vez. Yo haría esto:1981991. Actualizo Next, React y React DOM;2002. Lanzo el codemod oficial;2013. Arreglé cambios importantes en `params`, `searchParams`, `cookies()`, `headers()` y `draftMode()`;2024. Migro `middleware.ts` a `proxy.ts`;2035. Reviso compilaciones y páginas críticas;2046. Habilito Componentes de caché en una sección donde el caché actualmente crea fricción;2057. Defino convenciones para etiquetas e invalidación;2068. Intento React Compiler por separado;2079. Comparación de métricas antes y después.208209La buena migración no es la que utiliza todas las funciones nuevas. Es lo que hace que el comportamiento de la aplicación sea más legible.210211## ¿Qué cambia en la forma de pensar?212213Lo más útil de Next.js 16 es que te obliga a nombrar mejor las intenciones. Una función no es simplemente "obtener el producto de la base de datos". Es "obtener el producto, puedo almacenarlo en caché durante horas, lo invalido con esta etiqueta". Un componente no es simplemente "renderizar la página". Es "este es el caparazón rápido, esta pieza es personal, esto viene en streaming".214215Al principio parece más trabajo. Entonces se convierte en una forma de calma. Las decisiones de desempeño ya no están ocultas en una combinación de valores predeterminados, heurísticas y memoria tribal. Están en el código.216217## Fuentes útiles218219- [Notas de la versión de Next.js 16](https://nextjs.org/blog/next-16)220- [Componentes de caché: documentos de Next.js](https://nextjs.org/docs/app/getting-started/cache-components)221- [usar caché - Next.js docs](https://nextjs.org/docs/app/api-reference/directives/use-cache)222- [Reaccionar compilador v1.0](https://react.dev/blog/2025/10/07/react-compiler-1)223
:Next.js 16, Componentes de caché y React Compiler: lo que realmente cambialines 1-223 (END) — press q to close