spinny:~/writing $ vim nextjs-16-cache-components.md
1~2Για χρόνια μια από τις πιο ενοχλητικές ερωτήσεις στο Next.js ήταν: "Είναι αυτή η σελίδα στατική ή δυναμική;". Φαίνεται σαν μια απλή ερώτηση, μέχρι να προσθέσετε μια κλήση στο `cookies()`, ένα `fetch` με διαφορετικές επιλογές, ένα πρόγραμμα-πελάτη βάσης δεδομένων, ένα CMS, ένα καλάθι αγορών ή ένα κομμάτι προσαρμοσμένου περιεχομένου.3~4Το Next.js 16 είναι ενδιαφέρον γιατί προσπαθεί να κάνει αυτή τη συζήτηση λιγότερο μυστηριώδη. Δεν εξαλείφει την πολυπλοκότητα, αλλά αλλάζει το νοητικό μοντέλο: οι διαδρομές είναι δυναμικές από προεπιλογή, η κρυφή μνήμη δηλώνει όπου χρειάζεται και το `Suspense` γίνεται ο φυσικός τρόπος για να συνθέσετε γρήγορα κελύφη με μέρη που παραμένουν φρέσκα.5~6Το χαρακτηριστικό που πρέπει να κατανοήσετε είναι τα στοιχεία της προσωρινής μνήμης. Το Stable Turbopack, το React Compiler, το `proxy.ts` και τα νέα API ακύρωσης είναι σημαντικά, αλλά περιστρέφονται γύρω από το ίδιο πρόβλημα: δημιουργία γρήγορων εφαρμογών χωρίς να χρειάζεται να μαντέψετε τι αποφάσισε το πλαίσιο στα παρασκήνια.7~8## Γιατί αυτό το πράγμα έχει σημασία9~10Σε μια πραγματική εφαρμογή δεν έχετε απλώς "στατικές σελίδες" και "δυναμικές σελίδες". Έχετε διαφορετικά κομμάτια με διαφορετικές ανάγκες.11~12Το φύλλο προϊόντος μπορεί να αλλάζει μερικές φορές την ημέρα. Η τιμή μπορεί να αλλάζει πιο συχνά. Η διαθεσιμότητα πρέπει να είναι σχεδόν ζωντανή. Το όνομα χρήστη είναι προσωπικό. Οι κριτικές μπορούν να μεταδοθούν σε ροή. Η πλαϊνή μπάρα μπορεί να είναι σταθερή. Το καλάθι όχι.13~14Εάν αντιμετωπίζετε τα πάντα ως μια μονάδα, καταλήγετε πάντα σε ένα από τα δύο άκρα:15~16- επιθετική προσωρινή αποθήκευση και κίνδυνος εμφάνισης παλαιών δεδομένων.17- δυναμική απόδοση παντού και απόδοση χειρότερη από όσο χρειάζεται.18~19Το Cache Components χρησιμεύει ακριβώς για την αποφυγή αυτής της λανθασμένης επιλογής.20~21## Το μοντέλο στην πράξη22~23Με `cacheComponents: true`, μπορείτε να δηλώσετε τι είναι προσωρινά αποθηκευμένο χρησιμοποιώντας `"use cache"`. Στη συνέχεια, μπορείτε να συσχετίσετε τη διάρκεια και τις ετικέτες με `cacheLife()` και `cacheTag()`. Τα δυναμικά μέρη παραμένουν δυναμικά και μπορούν να απομονωθούν με `Suspense`.24~25```mermaid26flowchart TD27 Request[Αίτημα χρήστη] --> Shell[Αποθηκευμένο κέλυφος]28 Request --> Dynamic[Δυναμικές τομές]29 Shell --> FirstPaint[Πρώτο γρήγορο περιεχόμενο]30 Dynamic --> Stream[Streaming μέσα στο Suspense]31 Stream --> Complete[Πλήρης σελίδα]32```33~34Η ρύθμιση είναι μικρή:35~36```typescript37// next.config.ts38import type { NextConfig } from 'next';39~40const nextConfig: NextConfig = {41 cacheComponents: true,42};43~44export default nextConfig;45```46~47Η μεγάλη αλλαγή δεν είναι στις ρυθμίσεις. Είναι στο πώς ξεκινάτε να γράφετε τα στοιχεία.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~93Η σελίδα δεν χρειάζεται να είναι ολόκληρη προσωρινή ή δυναμική. Το φύλλο προϊόντος μπορεί να είναι γρήγορο και επαναχρησιμοποιήσιμο. Το απόθεμα μπορεί να παραμείνει φρέσκο. Ο χρήστης βλέπει κάτι αμέσως, χωρίς να περιμένει το πιο αργό μέρος.94~95## Το `use cache` είναι εκτελέσιμη τεκμηρίωση96~97Αυτό που μου αρέσει στο `"use cache"` είναι ότι σε αναγκάζει να κάνεις μια ρητή πρόθεση. Όταν διαβάζετε μια συνάρτηση, καταλαβαίνετε αμέσως ότι κάποιος αποφάσισε: "αυτά τα δεδομένα μπορούν να επαναχρησιμοποιηθούν".98~99Είναι ιδιαίτερα χρήσιμο όταν δεν χρησιμοποιείτε `fetch`. Πολλές εφαρμογές διαβάζουν δεδομένα από Prisma, Drizzle, εσωτερικά SDK, πελάτες CMS ή λειτουργίες υπηρεσιών. Σε αυτές τις περιπτώσεις η παλιά συλλογιστική που βασιζόταν μόνο στις επιλογές `fetch` δεν ήταν αρκετή.100~101Ένας εμπειρικός κανόνας:102~103- περιεχόμενο cachea σχετικά σταθερό.104- Χρησιμοποιήστε κοκκώδεις ετικέτες.105- αφήνει δυναμικά δικαιώματα, περιόδους σύνδεσης, καλάθια, ειδοποιήσεις και καταστάσεις συναλλαγών.106- βάλτε αργά εξαρτήματα μέσα `Suspense`.107- μετρήστε πριν πείτε "βελτιώσαμε την απόδοση".108~109## Ακυρώστε χωρίς να τα πετάξετε όλα110~111Η κρυφή μνήμη είναι χρήσιμη μόνο εάν μπορείτε να την ενημερώσετε με ακρίβεια. Εδώ τα `cacheTag`, `revalidateTag` και `updateTag` γίνονται σημαντικά.112~113Παράδειγμα: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~130Η σημαντική λεπτομέρεια είναι η ετικέτα. Το `product:${productId}` λέει ένα ακριβές όριο. Το `products` λέει έναν τεράστιο κουβά. Στην αρχή ο τεράστιος κάδος είναι άνετος. μετά από μερικούς μήνες γίνεται ο λόγος που ακυρώνετε μισή εφαρμογή για να αλλάξετε έναν τίτλο.131~132## Stable Turbopack: το κομμάτι που ακούτε κάθε μέρα133~134Το Next.js 16 φέρνει το Turbopack στο κέντρο για ανάπτυξη και κατασκευή. Δεν είναι το πιο ποιητικό χαρακτηριστικό, αλλά είναι αυτό που νιώθεις ενώ εργάζεσαι: διακομιστής που ξεκινά νωρίτερα, ταχύτερη ανανέωση, δομές που σταματούν να αισθάνονται σαν ένα αναγκαστικό διάλειμμα για καφέ.135~136Τούτου λεχθέντος, δεν θα μετεγκαταστήσω μια βάση κώδικα γεμάτη προσαρμοσμένες προσθήκες με κλειστά μάτια. θα ελεγχα:137~138- τοπική κατασκευή?139- μη τυποποιημένη εισαγωγή?140- MDX, SVG και CSS.141- Απομένουν προσθήκες πακέτου ιστού.142- κρίσιμες σελίδες?143- διαφορές στους χρόνους κατασκευής.144~145Για νέα έργα, θα ξεκινούσα από την προεπιλογή. Για τους ώριμους, θα έκανα μια μετρημένη μετανάστευση.146~147## React Compiler: αφαιρέστε το θόρυβο, όχι τη σκέψη148~149Το React Compiler 1.0 είναι σταθερό και το Next.js 16 το υποστηρίζει με `reactCompiler`. Η υπόσχεση είναι να μειωθεί πολύ η χειροκίνητη απομνημόνευση: λιγότερα `memo`, λιγότερα `useMemo`, λιγότερα `useCallback` που χρησιμοποιούνται "για ασφάλεια".150~151```typescript152// next.config.ts153import type { NextConfig } from 'next';154~155const nextConfig: NextConfig = {156 reactCompiler: true,157};158~159export default nextConfig;160```161~162Δεν θα το αντιμετώπιζα σαν μαγική σκόνη. Ο μεταγλωττιστής βοηθάει όταν ο κώδικας ακολουθεί καλά τους κανόνες του React. Εάν τα εξαρτήματα έχουν περίεργες παρενέργειες, κρυφές μεταλλάξεις ή κακώς χρησιμοποιημένα άγκιστρα, αυτό πρέπει πρώτα να διορθωθεί.163~164Ο υγιεινός τρόπος για να το δοκιμάσετε:165~1661. ενημέρωση `eslint-plugin-react-hooks`;1672. διόρθωση πραγματικών παραβιάσεων·1683. ενεργοποιήστε το σε ελεγχόμενη περιοχή.1694. Μέτρηση του χρόνου κατασκευής και της συμπεριφοράς.1705. αφαιρέστε τη χειροκίνητη απομνημόνευση μόνο όταν δεν είναι πλέον απαραίτητη.171~172Ο στόχος δεν είναι να σβήσετε κάθε `useMemo`. Ο στόχος είναι να σταματήσουμε να γράφουμε προληπτική απομνημόνευση γιατί φοβόμαστε την απόδοση.173~174## `proxy.ts` και το όριο δικτύου175~176Το παλιό `middleware.ts` γίνεται `proxy.ts`. Είναι μια αλλαγή ονόματος, αλλά είναι λογικό: αυτό το αρχείο βρίσκεται στο όριο αιτήματος, δεν είναι παραδοσιακό γενικό ενδιάμεσο λογισμικό τύπου 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~193Ο κανόνας εδώ είναι απλός: κρατήστε το μικρό. Ανακατεύθυνση, δρομολόγηση εξουσιοδότησης, κεφαλίδες, βασικές επανεγγραφές. Αν αρχίσει να φαίνεται σαν δεύτερο backend, μάλλον κάνει πάρα πολλά.194~195## Πώς πραγματικά θα μεταναστεύσω196~197Δεν θα ενεργοποιούσα όλες τις λειτουργίες ταυτόχρονα. Θα έκανα αυτό:198~1991. Ενημερώνω το Next, το React και το React DOM.2002. Ξεκινάω το επίσημο codemod.2013. Διορθώνω τις αλλαγές σπασίματος στα `params`, `searchParams`, `cookies()`, `headers()` και `draftMode()`;2024. Κάνω μετεγκατάσταση `middleware.ts` σε `proxy.ts`;2035. Ελέγχω κατασκευές και κρίσιμες σελίδες.2046. Ενεργοποιώ τα στοιχεία προσωρινής μνήμης σε μια ενότητα όπου η κρυφή μνήμη δημιουργεί τριβή.2057. Ορίζω συμβάσεις για ετικέτες και ακύρωση.2068. Δοκιμάζω το React Compiler ξεχωριστά.2079. σύγκριση μετρήσεων πριν και μετά.208~209Η καλή μετανάστευση δεν είναι αυτή που χρησιμοποιεί όλες τις νέες δυνατότητες. Αυτό είναι που κάνει τη συμπεριφορά της εφαρμογής πιο ευανάγνωστη.210~211## Τι αλλάζει στον τρόπο σκέψης212~213Το πιο χρήσιμο πράγμα για το Next.js 16 είναι ότι σας αναγκάζει να ονομάσετε καλύτερα τις προθέσεις. Μια συνάρτηση δεν είναι απλώς "πάρτε το προϊόν από τη βάση δεδομένων". Είναι "πάρτε το προϊόν, μπορώ να το κάνω cache για ώρες, το ακυρώνω με αυτήν την ετικέτα". Ένα στοιχείο δεν είναι απλώς "απόδοση της σελίδας". Είναι "αυτό είναι το γρήγορο κέλυφος, αυτό το κομμάτι είναι προσωπικό, αυτό έρχεται σε ροή."214~215Στην αρχή φαίνεται σαν περισσότερη δουλειά. Τότε γίνεται μια μορφή ηρεμίας. Οι αποφάσεις απόδοσης δεν κρύβονται πλέον σε έναν συνδυασμό προεπιλογών, ευρετικών και φυλετικής μνήμης. Είναι στον κώδικα.216~217## Χρήσιμες πηγές218~219- [Σημειώσεις έκδοσης Next.js 16](https://nextjs.org/blog/next-16)220- [Στοιχεία προσωρινής μνήμης - Έγγραφα Next.js](https://nextjs.org/docs/app/getting-started/cache-components)221- [χρήση προσωρινής μνήμης - Έγγραφα 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