spinny:~/writing $ less nextjs-16-cache-components.md
12Протягом багатьох років одним із найбільш неприємних запитань у Next.js було: «Ця сторінка статична чи динамічна?». Це здається простим запитанням, доки ви не додасте виклик до `cookies()`, `fetch` з різними параметрами, клієнта бази даних, CMS, кошика для покупок або частини спеціального вмісту.34Next.js 16 цікавий тим, що він намагається зробити цю розмову менш загадковою. Це не усуває складності, але змінює ментальну модель: маршрути динамічні за замовчуванням, кеш оголошує себе там, де потрібно, а `Suspense` стає природним способом створення швидких оболонок із частинами, які залишаються свіжими.56Функція для розуміння — це компоненти кешу. Стабільний Turbopack, React Compiler, `proxy.ts` і нові API недійсності є важливими, але вони пов’язані з тією самою проблемою: створення швидких додатків без необхідності здогадуватися, що фреймворк вирішив за лаштунками.78## Тому що ця річ має значення910У реальному додатку ви маєте не лише «статичні» та «динамічні сторінки». У вас є різні предмети з різними потребами.1112Аркуш товару може змінюватися кілька разів на день. Ціна може змінюватися частіше. Доступність має бути майже живою. Ім'я користувача персональне. Відгуки можна транслювати. Бічна панель може бути стійкою. Візок ні.1314Якщо розглядати все як одне ціле, ви завжди потрапляєте в одну з двох крайнощів:1516- агресивне кешування та ризик побачити старі дані;17- динамічний рендер скрізь і продуктивність нижча, ніж потрібно.1819Компоненти кешу служать саме для того, щоб уникнути цього помилкового вибору.2021## Модель на практиці2223За допомогою `cacheComponents: true` ви можете оголосити те, що кешується, за допомогою `"use cache"`. Потім ви можете пов’язати тривалість і теги з `cacheLife()` і `cacheTag()`. Динамічні частини залишаються динамічними та можуть бути ізольовані за допомогою `Suspense`.2425```mermaid26flowchart TD27 Request[Запит користувача] --> Shell[Кешована оболонка]28 Request --> Dynamic[Динамічні розділи]29 Shell --> FirstPaint[Перший швидкий контент]30 Dynamic --> Stream[Трансляція всередині саспенсу]31 Stream --> Complete[Повна сторінка]32```3334Налаштування невелике:3536```typescript37// next.config.ts38import type { NextConfig } from 'next';3940const nextConfig: NextConfig = {41 cacheComponents: true,42};4344export default nextConfig;45```4647Велика зміна не в конфігурації. Справа в тому, як ви починаєте писати компоненти.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```9293Сторінка не обов’язково має бути повністю кешованою або повністю динамічною. Аркуш продукту може бути швидким і багаторазовим. Інвентар може залишатися свіжим. Користувач бачить щось відразу, не чекаючи найповільнішої частини.9495## `use cache` є виконуваною документацією9697Мені подобається в `"use cache"` те, що він змушує вас чітко висловити намір. Коли читаєш функцію, одразу розумієш, що хтось вирішив: «ці дані можна повторно використовувати».9899Це особливо корисно, коли ви не використовуєте `fetch`. Багато програм читають дані з Prisma, Drizzle, внутрішніх SDK, клієнтів CMS або сервісних функцій. У цих випадках старих міркувань, заснованих лише на `fetch` варіантах, було недостатньо.100101Основне правило:102103- вміст cachea відносно стабільний;104- використовувати гранульовані теги;105- залишає динамічні дозволи, сеанси, кошики, сповіщення та стани транзакцій;106- помістити повільні частини всередину `Suspense`;107- виміряти, перш ніж сказати "ми покращили продуктивність".108109## Анулюйте, не викидаючи всього110111Кеш корисний, лише якщо ви можете його точно оновити. Тут важливі `cacheTag`, `revalidateTag` і `updateTag`.112113приклад: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```129130Важливою деталлю є тег. `product:${productId}` вказує точну межу. `products` розповідає величезне відро. Спочатку величезне відро зручно; через кілька місяців це стає причиною, через яку ви скасуєте половину програми, щоб змінити назву.131132## Стабільний Turbopack: те, що ви чуєте щодня133134Next.js 16 переносить Turbopack у центр розробки та створення. Це не найпоетичніша функція, але це та, яку ви відчуваєте під час роботи: сервер, який запускається раніше, швидше оновлення, збірки, які перестають відчувати себе як вимушена перерва на каву.135136Тим не менш, я б не переніс кодову базу, повну нестандартних плагінів із заплющеними очима. Я б перевірив:137138- місцева конструкція;139- нестандартний імпорт;140- MDX, SVG і CSS;141- Плагіни Webpack залишилися;142- критичні сторінки;143- відмінності в часі будівництва.144145Для нових проектів я б почав із замовчуванням. Для зрілих я б зробив розмірену міграцію.146147## Компілятор React: видалити шум, а не думку148149Компілятор React 1.0 стабільний, а Next.js 16 підтримує його за допомогою `reactCompiler`. Обіцянка полягає в тому, щоб скоротити багато запам’ятовування вручну: менше `memo`, менше `useMemo`, менше `useCallback`, які використовуються «для безпеки».150151```typescript152// next.config.ts153import type { NextConfig } from 'next';154155const nextConfig: NextConfig = {156 reactCompiler: true,157};158159export default nextConfig;160```161162Я б не ставився до нього як до чарівного пилу. Компілятор допомагає, коли код добре дотримується правил React. Якщо компоненти мають дивні побічні ефекти, приховані мутації або погано використовувані хуки, це потрібно спочатку виправити.163164Здоровий спосіб спробувати:1651661. оновлення `eslint-plugin-react-hooks`;1672. фіксувати фактичні порушення;1683. включити його на контрольованій території;1694. виміряти час побудови та поведінку;1705. видалити ручне запам'ятовування лише тоді, коли воно більше не потрібно.171172Мета полягає не в тому, щоб стерти кожен `useMemo`. Мета полягає в тому, щоб припинити писати превентивну мемоізацію, тому що ми боїмося рендерингу.173174## `proxy.ts` та межі мережі175176Старий `middleware.ts` стає `proxy.ts`. Це зміна назви, але це має сенс: цей файл знаходиться на межі запиту, це не традиційне базове проміжне програмне забезпечення.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```192193Правило тут просте: тримайте його маленьким. Перенаправлення, автентифікація маршрутизації, заголовки, основні перезаписи. Якщо він починає здаватися другим серверним модулем, ймовірно, він робить занадто багато.194195## Як би я дійсно мігрував196197Я б не став вмикати всі функції відразу. Я б зробив так:1981991. Я оновлю Next, React і React DOM;2002. Я запускаю офіційний codemod;2013. Я виправляю критичні зміни в `params`, `searchParams`, `cookies()`, `headers()` та `draftMode()`;2024. Я переношу `middleware.ts` до `proxy.ts`;2035. Я перевіряю збірки та критичні сторінки;2046. Я вмикаю компоненти кешу в розділі, де кеш зараз створює тертя;2057. Я визначаю умови для тегів і недійсності;2068. Я пробую компілятор React окремо;2079. порівняння показників до і після.208209Хороша міграція – це не та, у якій використовуються всі нові функції. Це те, що робить поведінку програми більш читабельною.210211## Що змінюється в способі мислення212213Найбільш корисним у Next.js 16 є те, що він змушує вас краще називати наміри. Функція — це не просто «отримати товар із бази даних». Це "отримайте продукт, я можу кешувати його годинами, я анулюю його цим тегом". Компонент – це не просто «відобразити сторінку». Це "це швидка оболонка, ця частина особиста, це транслюється".214215Спочатку здається, що роботи більше. Тоді це стає формою спокою. Рішення щодо продуктивності більше не приховані в поєднанні стандартних значень, евристики та племінної пам’яті. Вони є в коді.216217## Корисні джерела218219- [Примітки до випуску 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 v1.0](https://react.dev/blog/2025/10/07/react-compiler-1)223
:Next.js 16, компоненти кешу та компілятор React: що насправді змінюєтьсяlines 1-223 (END) — press q to close