spinny:~/writing $ vim nextjs-16-cache-components.md
1~2Przez lata jednym z najbardziej irytujących pytań w Next.js było: „Czy ta strona jest statyczna czy dynamiczna?”. Wydaje się to prostym pytaniem, dopóki nie dodasz wywołania do `cookies()`, `fetch` z różnymi opcjami, klienta bazy danych, CMS, koszyka lub fragmentu niestandardowej treści.3~4Next.js 16 jest interesujący, ponieważ stara się uczynić tę rozmowę mniej tajemniczą. Nie eliminuje to złożoności, ale zmienia model mentalny: trasy są domyślnie dynamiczne, pamięć podręczna deklaruje się tam, gdzie jest to potrzebne, a `Suspense` staje się naturalnym sposobem komponowania szybkich powłok z części, które pozostają świeże.5~6Cechą, którą należy zrozumieć, są komponenty pamięci podręcznej. Stable Turbopack, React Compiler, `proxy.ts` i nowe interfejsy API unieważniające są ważne, ale dotyczą tego samego problemu: tworzenia szybkich aplikacji bez konieczności zgadywania, co framework zdecydował za kulisami.7~8## Ponieważ ta rzecz ma znaczenie9~10W prawdziwej aplikacji nie masz tylko „stron statycznych” i „stron dynamicznych”. Masz różne elementy i różne potrzeby.11~12Karta produktu może zmieniać się kilka razy dziennie. Cena może zmieniać się częściej. Dostępność musi być prawie aktywna. Nazwa użytkownika jest osobista. Recenzje można przesyłać strumieniowo. Pasek boczny może być stabilny. Wózek nie.13~14Jeśli potraktujesz wszystko jako jedną całość, zawsze znajdziesz się w jednej z dwóch skrajności:15~16- agresywne buforowanie i ryzyko zobaczenia starych danych;17- dynamiczne renderowanie wszędzie i wydajność gorsza niż to konieczne.18~19Cache Components służy właśnie do uniknięcia tego fałszywego wyboru.20~21## Model w praktyce22~23Za pomocą `cacheComponents: true` możesz zadeklarować, co można buforować, używając `"use cache"`. Następnie możesz powiązać czas trwania i znaczniki z `cacheLife()` i `cacheTag()`. Części dynamiczne pozostają dynamiczne i można je odizolować za pomocą `Suspense`.24~25```mermaid26flowchart TD27 Request[Żądanie użytkownika] --> Shell[Powłoka buforowana]28 Request --> Dynamic[Sekcje dynamiczne]29 Shell --> FirstPaint[Pierwsza szybka treść]30 Dynamic --> Stream[Transmisja strumieniowa w napięciu]31 Stream --> Complete[Pełna strona]32```33~34Konfiguracja jest niewielka:35~36```typescript37// next.config.ts38import type { NextConfig } from 'next';39~40const nextConfig: NextConfig = {41 cacheComponents: true,42};43~44export default nextConfig;45```46~47Duża zmiana nie dotyczy konfiguracji. Wszystko zależy od tego, jak zaczniesz pisać komponenty.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~93Strona nie musi być w całości buforowana ani dynamiczna. Karta produktu może być szybka i wielokrotnego użytku. Zapasy mogą pozostać świeże. Użytkownik widzi coś od razu, nie czekając na najwolniejszą część.94~95## `use cache` to dokumentacja wykonywalna96~97To, co podoba mi się w `"use cache"`, to to, że zmusza cię do wyraźnego wyrażenia swojej intencji. Kiedy czytasz funkcję, od razu rozumiesz, że ktoś zdecydował: „te dane można ponownie wykorzystać”.98~99Jest to szczególnie przydatne, gdy nie używasz `fetch`. Wiele aplikacji odczytuje dane z Prisma, Drizzle, wewnętrznych zestawów SDK, klientów CMS lub funkcji usługowych. W takich przypadkach stare rozumowanie oparte wyłącznie na opcjach `fetch` nie wystarczyło.100~101Praktyczna zasada:102~103- zawartość pamięci podręcznej stosunkowo stabilna;104- używaj szczegółowych tagów;105- pozostawia dynamiczne uprawnienia, sesje, koszyki, powiadomienia i stany transakcyjne;106- umieść powolne części wewnątrz `Suspense`;107- zmierzyć, zanim powiesz „poprawiliśmy wydajność”.108~109## Unieważnij bez wyrzucania wszystkiego110~111Pamięć podręczna jest użyteczna tylko wtedy, gdy możesz ją dokładnie zaktualizować. Tutaj `cacheTag`, `revalidateTag` i `updateTag` stają się ważne.112~113Przykład: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~130Ważnym szczegółem jest metka. `product:${productId}` wyznacza dokładną granicę. `products` mówi ogromnemu wiadro. Na początku ogromne wiadro jest wygodne; po kilku miesiącach staje się to powodem unieważnienia połowy aplikacji w celu zmiany tytułu.131~132## Stabilny Turbopack: część, którą słyszysz każdego dnia133~134Next.js 16 przenosi Turbopack do centrum rozwoju i kompilacji. Nie jest to może najbardziej poetycka cecha, ale odczuwa się ją podczas pracy: serwer uruchamia się wcześniej, szybsze odświeżanie, kompilacje przestają przypominać wymuszoną przerwę na kawę.135~136To powiedziawszy, nie migrowałbym bazy kodu pełnej niestandardowych wtyczek z zamkniętymi oczami. sprawdziłbym:137~138- kompilacja lokalna;139- niestandardowe importy;140- MDX, SVG i CSS;141- Pozostały wtyczki pakietu internetowego;142- strony krytyczne;143- różnice w czasie budowy.144~145W przypadku nowych projektów zacząłbym od ustawień domyślnych. W przypadku dojrzałych przeprowadziłbym migrację odmierzoną.146~147## React Compiler: usuń hałas, a nie myśl148~149React Compiler 1.0 jest stabilny, a Next.js 16 obsługuje go za pomocą `reactCompiler`. Obietnica polega na zmniejszeniu ilości ręcznego zapamiętywania: mniej `memo`, mniej `useMemo`, mniej `useCallback` używanych „dla bezpieczeństwa”.150~151```typescript152// next.config.ts153import type { NextConfig } from 'next';154~155const nextConfig: NextConfig = {156 reactCompiler: true,157};158~159export default nextConfig;160```161~162Nie traktowałbym go jak magicznego pyłu. Kompilator pomaga, gdy kod jest zgodny z regułami React. Jeśli komponenty mają dziwne skutki uboczne, ukryte mutacje lub źle używane hooki, należy to najpierw naprawić.163~164Zdrowy sposób, aby spróbować:165~1661. aktualizacja `eslint-plugin-react-hooks`;1672. naprawić faktyczne naruszenia;1683. włącz to na kontrolowanym obszarze;1694. mierzyć czas i zachowanie kompilacji;1705. usuwaj ręczne zapamiętywanie tylko wtedy, gdy nie jest już potrzebne.171~172Celem nie jest usunięcie każdego `useMemo`. Celem jest zaprzestanie pisania zapamiętywania zapobiegawczego, ponieważ boimy się renderowania.173~174## `proxy.ts` i granicę sieci175~176Stary `middleware.ts` staje się `proxy.ts`. To zmiana nazwy, ale ma to sens: ten plik znajduje się na granicy żądania, a nie jest to tradycyjne, ogólne oprogramowanie pośredniczące w stylu backendu.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~193Zasada jest tutaj prosta: trzymaj się małych rozmiarów. Przekierowanie, routing uwierzytelniania, nagłówki, niezbędne przeróbki. Jeśli zaczyna sprawiać wrażenie drugiego backendu, prawdopodobnie robi za dużo.194~195## Jak naprawdę miałbym wyemigrować196~197Nie włączałbym wszystkich funkcji na raz. Zrobiłbym to:198~1991. Aktualizuję Next, React i React DOM;2002. Uruchamiam oficjalny codemod;2013. Naprawiam istotne zmiany w `params`, `searchParams`, `cookies()`, `headers()` i `draftMode()`;2024. Przeprowadzam migrację `middleware.ts` do `proxy.ts`;2035. Sprawdzam kompilacje i krytyczne strony;2046. Włączam komponenty pamięci podręcznej w sekcji, w której pamięć podręczna powoduje obecnie tarcia;2057. Definiuję konwencje dotyczące znaczników i unieważniania;2068. Próbuję oddzielnie React Compiler;2079. porównanie wskaźników przed i po.208~209Dobra migracja to nie ta, która wykorzystuje wszystkie nowe funkcje. To sprawia, że zachowanie aplikacji jest bardziej czytelne.210~211## Co się zmienia w sposobie myślenia212~213Najbardziej użyteczną rzeczą w Next.js 16 jest to, że zmusza Cię do lepszego nazywania intencji. Funkcja to nie tylko „pobranie produktu z bazy danych”. To „zdobądź produkt, mogę go buforować godzinami, unieważniam go tym tagiem”. Komponent to nie tylko „renderowanie strony”. To „to jest szybka powłoka, ten utwór jest osobisty, to jest przesyłane strumieniowo”.214~215Na początku wydaje się, że jest więcej pracy. Wtedy staje się to formą spokoju. Decyzje dotyczące wydajności nie są już ukryte w kombinacji ustawień domyślnych, heurystyki i pamięci plemiennej. Są w kodzie.216~217## Przydatne źródła218~219- [Informacje o wydaniu Next.js 16](https://nextjs.org/blog/next-16)220- [Składniki pamięci podręcznej — dokumentacja Next.js](https://nextjs.org/docs/app/getting-started/cache-components)221- [użyj pamięci podręcznej - dokumentacja Next.js](https://nextjs.org/docs/app/api-reference/directives/use-cache)222- [Kompilator reakcji 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