spinny:~/writing $ vim nextjs-16-cache-components.md
1~2De ani de zile, una dintre cele mai enervante întrebări din Next.js a fost: „Este această pagină statică sau dinamică?”. Pare o întrebare simplă, până când adăugați un apel la `cookies()`, un `fetch` cu diferite opțiuni, un client de bază de date, un CMS, un coș de cumpărături sau o bucată de conținut personalizat.3~4Next.js 16 este interesant, deoarece încearcă să facă această conversație mai puțin misterioasă. Nu elimină complexitatea, dar schimbă modelul mental: rutele sunt dinamice implicit, cache-ul se declară acolo unde este nevoie, iar `Suspense` devine modalitatea naturală de a compune shell-uri rapide cu părți care rămân proaspete.5~6Caracteristica de înțeles este Componentele cache. Stable Turbopack, React Compiler, `proxy.ts` și noile API-uri de invalidare sunt importante, dar se învârte în jurul aceleiași probleme: construirea de aplicații rapide fără a fi nevoie să ghicească ce a decis cadrul în culise.7~8## Pentru că chestia asta contează9~10Într-o aplicație reală nu aveți doar „pagini statice” și „pagini dinamice”. Aveți piese diferite cu nevoi diferite.11~12Fișa produsului se poate schimba de câteva ori pe zi. Prețul se poate schimba mai des. Disponibilitatea trebuie să fie aproape live. Numele de utilizator este personal. Recenziile pot fi transmise în flux. Bara laterală poate fi stabilă. Căruciorul nu.13~14Dacă tratezi totul ca o singură unitate, ajungi întotdeauna în una dintre cele două extreme:15~16- stocarea în cache agresivă și riscul de a vedea date vechi;17- randare dinamică peste tot și performanță mai slabă decât este necesar.18~19Cache Components servește tocmai pentru a evita această alegere falsă.20~21## Modelul în practică22~23Cu `cacheComponents: true`, puteți declara ceea ce poate fi stocat în cache folosind `"use cache"`. Apoi puteți asocia durata și etichetele cu `cacheLife()` și `cacheTag()`. Părțile dinamice rămân dinamice și pot fi izolate cu `Suspense`.24~25```mermaid26flowchart TD27 Request[Solicitarea utilizatorului] --> Shell[Shell în cache]28 Request --> Dynamic[Secțiuni dinamice]29 Shell --> FirstPaint[Primul conținut rapid]30 Dynamic --> Stream[Streaming în interiorul Suspans]31 Stream --> Complete[Pagina intreaga]32```33~34Configurația este mică:35~36```typescript37// next.config.ts38import type { NextConfig } from 'next';39~40const nextConfig: NextConfig = {41 cacheComponents: true,42};43~44export default nextConfig;45```46~47Marea schimbare nu este în configurație. Este în modul în care începi să scrii componentele.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~93Pagina nu trebuie să fie în totalitate în cache sau dinamică. Fișa produsului poate fi rapidă și reutilizabilă. Inventarul poate rămâne proaspăt. Utilizatorul vede ceva imediat, fără să aștepte partea cea mai lentă.94~95## `use cache` este o documentație executabilă96~97Lucrul care îmi place la `"use cache"` este că te obligă să explici o intenție. Când citești o funcție, înțelegi imediat că cineva a decis: „aceste date pot fi refolosite”.98~99Este util mai ales când nu utilizați `fetch`. Multe aplicații citesc date de la Prisma, Drizzle, SDK-uri interne, clienți CMS sau funcții de serviciu. În acele cazuri, vechiul raționament bazat doar pe opțiunile `fetch` nu a fost suficient.100~101O regulă generală:102~103- conținutul cacheei relativ stabil;104- utilizați etichete granulare;105- lasă permisiuni dinamice, sesiuni, cărucioare, notificări și stări tranzacționale;106- pune piese lente în interiorul `Suspense`;107- măsurați înainte de a spune „am îmbunătățit performanța”.108~109## Invalidați fără a arunca totul110~111Cache-ul este util doar dacă îl puteți actualiza cu precizie. Aici `cacheTag`, `revalidateTag` și `updateTag` devin importante.112~113Exemplu: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~130Detaliul important este eticheta. `product:${productId}` indică o limită precisă. `products` spune unei găleți uriașe. La început găleata uriașă este confortabilă; după câteva luni devine motivul pentru care invalidezi o jumătate de aplicație pentru a schimba un titlu.131~132## Turbopack stabil: partea pe care o auzi în fiecare zi133~134Next.js 16 aduce Turbopack în centrul dezvoltării și construirii. Nu este cea mai poetică caracteristică, dar este cea pe care o simți în timp ce lucrezi: server care pornește mai devreme, reîmprospătare mai rapidă, build-uri care nu se mai simt ca o pauză de cafea forțată.135~136Acestea fiind spuse, nu aș migra o bază de cod plină de pluginuri personalizate cu ochii închiși. as verifica:137~138- construcție locală;139- module non-standard;140- MDX, SVG și CSS;141- Pluginuri Webpack rămase;142- pagini critice;143- diferențe de timp de construcție.144~145Pentru proiecte noi, aș începe de la implicit. Pentru cei maturi aș face o migrație măsurată.146~147## React Compiler: eliminați zgomotul, nu gândirea148~149React Compiler 1.0 este stabil și Next.js 16 îl acceptă cu `reactCompiler`. Promisiunea este reducerea multă memorare manuală: mai puțin `memo`, mai puțin `useMemo`, mai puțin `useCallback` folosit „pentru siguranță”.150~151```typescript152// next.config.ts153import type { NextConfig } from 'next';154~155const nextConfig: NextConfig = {156 reactCompiler: true,157};158~159export default nextConfig;160```161~162Nu l-aș trata ca pe un praf magic. Compilatorul ajută atunci când codul respectă bine regulile React. Dacă componentele au efecte secundare ciudate, mutații ascunse sau cârlige prost folosite, trebuie remediat mai întâi.163~164Modul sănătos de a-l încerca:165~1661. actualizare `eslint-plugin-react-hooks`;1672. remediați încălcările reale;1683. activați-l pe o zonă controlată;1694. măsurați timpul de construcție și comportamentul;1705. eliminați memorarea manuală numai atunci când nu mai este necesară.171~172Scopul este să nu ștergeți fiecare `useMemo`. Scopul este să nu mai scriem memorări preventive pentru că ne este frică de redare.173~174## `proxy.ts` și limita rețelei175~176Vechiul `middleware.ts` devine `proxy.ts`. Este o schimbare de nume, dar are sens: acel fișier se află la limita cererii, nu este un middleware generic tradițional în stil backend.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~193Regula aici este simplă: păstrați-l mic. Redirecționare, rutare autentificare, anteturi, rescrieri esențiale. Dacă începe să pară un al doilea backend, probabil că face prea mult.194~195## Cum aș migra cu adevărat196~197Nu aș activa toate funcțiile deodată. as face asta:198~1991. Actualizez Next, React și React DOM;2002. Lansez codul oficial;2013. Repar modificările de ruptură pe `params`, `searchParams`, `cookies()`, `headers()` și `draftMode()`;2024. Migrez `middleware.ts` la `proxy.ts`;2035. Verific versiunile și paginile critice;2046. Activez Componentele cache într-o secțiune în care memoria cache creează în prezent frecare;2057. Definesc convenții pentru etichete și invalidare;2068. Încerc React Compiler separat;2079. compararea valorilor înainte și după.208~209Migrarea bună nu este cea care folosește toate funcțiile noi. Este ceea ce face comportamentul aplicației mai lizibil.210~211## Ce se schimbă în modul de gândire212~213Cel mai util lucru despre Next.js 16 este că te obligă să numești mai bine intențiile. O funcție nu este doar „obține produsul din baza de date”. Este „primiți produsul, îl pot păstra în cache ore în șir, îl invalidez cu această etichetă”. O componentă nu este doar „redarea paginii”. Este „aceasta este carcasa rapidă, această piesă este personală, aceasta vine în streaming”.214~215La început pare mai multă muncă. Apoi devine o formă de calm. Deciziile de performanță nu mai sunt ascunse într-o combinație de valori implicite, euristică și memorie tribală. Sunt în cod.216~217## Surse utile218~219- [Note de lansare Next.js 16](https://nextjs.org/blog/next-16)220- [Componente cache - documente Next.js](https://nextjs.org/docs/app/getting-started/cache-components)221- [utilizați memoria cache - documente Next.js](https://nextjs.org/docs/app/api-reference/directives/use-cache)222- [React Compiler 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