spinny:~/writing $ less nextjs-16-cache-components.md
12I flera år har en av de mest irriterande frågorna i Next.js varit: "Är den här sidan statisk eller dynamisk?". Det verkar som en enkel fråga, tills du lägger till ett anrop till `cookies()`, en `fetch` med olika alternativ, en databasklient, ett CMS, en kundvagn eller ett stycke anpassat innehåll.34Next.js 16 är intressant eftersom det försöker göra den här konversationen mindre mystisk. Det eliminerar inte komplexitet, men det förändrar den mentala modellen: rutter är dynamiska som standard, cachen deklarerar sig själv där det behövs och `Suspense` blir det naturliga sättet att komponera snabba skal med delar som håller sig fräscha.56Funktionen att förstå är Cache-komponenter. Stabil Turbopack, React Compiler, `proxy.ts` och de nya invaliderings-API:erna är viktiga, men de kretsar kring samma problem: att bygga snabba appar utan att behöva gissa vad ramverket beslutade bakom kulisserna.78## För det här spelar roll910I en riktig app har du inte bara "statiska sidor" och "dynamiska sidor". Du har olika pjäser med olika behov.1112Produktbladet kan ändras några gånger om dagen. Priset kan ändras oftare. Tillgänglighet måste vara nästan live. Användarnamnet är personligt. Recensioner kan streamas. Sidofältet kan vara stabilt. Det gör inte vagnen.1314Om du behandlar allt som en enhet hamnar du alltid i en av två ytterligheter:1516- aggressiv cachning och risk för att se gamla data;17- dynamisk rendering överallt och prestanda sämre än nödvändigt.1819Cache-komponenter tjänar just till att undvika detta felaktiga val.2021## Modellen i praktiken2223Med `cacheComponents: true` kan du deklarera vad som är cachebart med `"use cache"`. Sedan kan du associera varaktighet och taggar med `cacheLife()` och `cacheTag()`. Dynamiska delar förblir dynamiska och kan isoleras med `Suspense`.2425```mermaid26flowchart TD27 Request[Användarförfrågan] --> Shell[Cachat skal]28 Request --> Dynamic[Dynamiska sektioner]29 Shell --> FirstPaint[Första snabba innehållet]30 Dynamic --> Stream[Streamar inuti Suspense]31 Stream --> Complete[Hela sidan]32```3334Inställningen är liten:3536```typescript37// next.config.ts38import type { NextConfig } from 'next';3940const nextConfig: NextConfig = {41 cacheComponents: true,42};4344export default nextConfig;45```4647Den stora förändringen finns inte i konfigurationen. Det är hur du börjar skriva komponenterna.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```9293Sidan behöver inte vara helt cachad eller helt dynamisk. Produktbladet kan vara snabbt och återanvändbart. Inventeringen kan hålla sig fräsch. Användaren ser något direkt, utan att vänta på den långsammaste delen.9495## `use cache` är körbar dokumentation9697Det jag gillar med `"use cache"` är att det tvingar dig att uttrycka en avsikt. När man läser en funktion förstår man direkt att någon har bestämt sig: "denna data kan återanvändas".9899Det är särskilt användbart när du inte använder `fetch`. Många appar läser data från Prisma, Drizzle, interna SDK:er, CMS-klienter eller servicefunktioner. I dessa fall räckte inte det gamla resonemanget baserat på `fetch`-alternativ.100101En tumregel:102103- cacheinnehåll relativt stabilt;104- använd granulära taggar;105- lämnar dynamiska behörigheter, sessioner, vagnar, meddelanden och transaktionstillstånd;106- lägg långsamma delar inuti `Suspense`;107- mäta innan du säger "vi förbättrade prestandan".108109## Ogiltigförklara utan att kasta allt110111Cachen är bara användbar om du kan uppdatera den korrekt. Här blir `cacheTag`, `revalidateTag` och `updateTag` viktiga.112113Exempel: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```129130Den viktiga detaljen är taggen. `product:${productId}` visar en exakt gräns. `products` säger en stor hink. Till en början är den enorma skopan bekväm; efter några månader blir det anledningen till att du ogiltigförklarar en halv app för att ändra en titel.131132## Stabil Turbopack: delen du hör varje dag133134Next.js 16 tar Turbopack till centrum för utveckling och konstruktion. Det är inte det mest poetiska inslaget, men det är den du känner medan du arbetar: server som startar tidigare, snabbare uppdatering, byggen som slutar kännas som en tvångsfika.135136Som sagt, jag skulle inte migrera en kodbas full av anpassade plugins med slutna ögon. Jag skulle kolla:137138- lokal byggnad;139- icke-standard import;140- MDX, SVG och CSS;141- Webpack plugins kvar;142- kritiska sidor;143- skillnader i byggtider.144145För nya projekt skulle jag börja från standard. För mogna skulle jag göra en uppmätt migration.146147## React Compiler: ta bort brus, inte tänkt148149React Compiler 1.0 är stabil och Next.js 16 stöder den med `reactCompiler`. Löftet är att minska mycket manuell memoisering: mindre `memo`, mindre `useMemo`, mindre `useCallback` används "för säkerhets skull".150151```typescript152// next.config.ts153import type { NextConfig } from 'next';154155const nextConfig: NextConfig = {156 reactCompiler: true,157};158159export default nextConfig;160```161162Jag skulle inte behandla det som ett magiskt damm. Kompilatorn hjälper till när koden följer React-reglerna väl. Om komponenter har konstiga biverkningar, dolda mutationer eller dåligt använda krokar, måste det åtgärdas först.163164Det hälsosamma sättet att prova det:1651661. uppdatera `eslint-plugin-react-hooks`;1672. fixa faktiska överträdelser;1683. aktivera det på ett kontrollerat område;1694. mäta byggtid och beteende;1705. ta bort manuell memoisering endast när den inte längre behövs.171172Målet är inte att radera varje `useMemo`. Målet är att sluta skriva förebyggande memoisering eftersom vi är rädda för rendering.173174## `proxy.ts` och nätverksgränsen175176Den gamla `middleware.ts` blir `proxy.ts`. Det är ett namnbyte, men det är vettigt: den filen ligger vid förfrågningsgränsen, det är inte traditionell mellanprogramvara i backend-stil.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```192193Regeln här är enkel: håll den liten. Omdirigering, autentiseringsdirigering, rubriker, viktiga omskrivningar. Om det börjar kännas som en andra backend, gör det förmodligen för mycket.194195## Hur jag verkligen skulle migrera196197Jag skulle inte slå på alla funktioner på en gång. Jag skulle göra så här:1981991. Jag uppdaterar Next, React och React DOM;2002. Jag startar den officiella codemoden;2013. Jag fixar brytande ändringar på `params`, `searchParams`, `cookies()`, `headers()` och `draftMode()`;2024. Jag migrerar `middleware.ts` till `proxy.ts`;2035. Jag kollar builds och kritiska sidor;2046. Jag aktiverar Cache-komponenter på en sektion där cachen för närvarande skapar friktion;2057. Jag definierar konventioner för taggar och ogiltigförklaring;2068. Jag försöker React Compiler separat;2079. jämförelse av mätvärden före och efter.208209Den goda migrationen är inte den som använder alla nya funktioner. Det är det som gör appens beteende mer läsbart.210211## Vad förändras i sättet att tänka212213Det mest användbara med Next.js 16 är att det tvingar dig att namnge avsikter bättre. En funktion är inte bara "hämta produkten från databasen". Det är "skaffa produkten, jag kan cache den i timmar, jag ogiltigförklarar den med den här taggen". En komponent är inte bara "rendera sidan". Det är "det här är det snabba skalet, det här stycket är personligt, det här kommer strömmande."214215Till en början verkar det som mer jobb. Då blir det en form av lugn. Prestandabeslut är inte längre dolda i en kombination av standardinställningar, heuristik och stamminne. De finns i koden.216217## Användbara källor218219- [Next.js 16 release notes](https://nextjs.org/blog/next-16)220- [Cachekomponenter - Next.js docs](https://nextjs.org/docs/app/getting-started/cache-components)221- [använd cache - Next.js docs](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
:Next.js 16, Cache-komponenter och React Compiler: vad som verkligen förändraslines 1-223 (END) — press q to close