spinny:~/writing $ less nextjs-16-cache-components.md
12Selama bertahun-tahun, salah satu pertanyaan paling menjengkelkan di Next.js adalah: "Apakah halaman ini statis atau dinamis?". Sepertinya pertanyaan sederhana, sampai Anda menambahkan panggilan ke `cookies()`, `fetch` dengan opsi berbeda, klien database, CMS, keranjang belanja, atau konten khusus.34Next.js 16 menarik karena mencoba membuat percakapan ini tidak terlalu misterius. Ini tidak menghilangkan kompleksitas, tetapi mengubah model mental: rute bersifat dinamis secara default, cache mendeklarasikan dirinya sendiri jika diperlukan, dan `Suspense` menjadi cara alami untuk menyusun shell cepat dengan bagian-bagian yang tetap segar.56Fitur yang perlu dipahami adalah Cache Components. Turbopack Stabil, React Compiler, `proxy.ts`, dan API invalidasi baru memang penting, namun semuanya berkisar pada masalah yang sama: membangun aplikasi cepat tanpa harus menebak apa yang diputuskan oleh framework di balik layar.78## Karena hal ini penting910Dalam aplikasi nyata Anda tidak hanya memiliki "halaman statis" dan "halaman dinamis". Anda memiliki bagian berbeda dengan kebutuhan berbeda.1112Lembar produk dapat berubah beberapa kali sehari. Harga mungkin akan lebih sering berubah. Ketersediaan harus hampir aktif. Nama pengguna bersifat pribadi. Ulasan dapat dialirkan. Sidebar bisa stabil. Gerobak tidak.1314Jika Anda memperlakukan segala sesuatu sebagai satu kesatuan, Anda selalu berakhir di salah satu dari dua ekstrem:1516- caching yang agresif dan risiko melihat data lama;17- rendering dinamis di mana-mana dan kinerja lebih buruk dari yang diperlukan.1819Komponen Cache berfungsi tepat untuk menghindari pilihan yang salah ini.2021## Model dalam praktiknya2223Dengan `cacheComponents: true`, Anda dapat mendeklarasikan apa yang dapat di-cache menggunakan `"use cache"`. Kemudian Anda dapat mengaitkan durasi dan tag dengan `cacheLife()` dan `cacheTag()`. Bagian dinamis tetap dinamis dan dapat diisolasi dengan `Suspense`.2425```mermaid26flowchart TD27 Request[Permintaan pengguna] --> Shell[Cangkang yang di-cache]28 Request --> Dynamic[Bagian dinamis]29 Shell --> FirstPaint[Konten cepat pertama]30 Dynamic --> Stream[Streaming di dalam Suspense]31 Stream --> Complete[Halaman penuh]32```3334Pengaturannya kecil:3536```typescript37// next.config.ts38import type { NextConfig } from 'next';3940const nextConfig: NextConfig = {41 cacheComponents: true,42};4344export default nextConfig;45```4647Perubahan besar bukan pada konfigurasinya. Itu tergantung bagaimana Anda mulai menulis komponen.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```9293Halaman tidak harus semuanya di-cache atau dinamis. Lembar produk dapat dibuat dengan cepat dan dapat digunakan kembali. Persediaan bisa tetap segar. Pengguna langsung melihat sesuatu, tanpa menunggu bagian paling lambat.9495## `use cache` adalah dokumentasi yang dapat dieksekusi9697Hal yang saya suka tentang `"use cache"` adalah ia memaksa Anda untuk menyatakan niat secara eksplisit. Saat Anda membaca suatu fungsi, Anda langsung memahami bahwa seseorang telah memutuskan: "data ini dapat digunakan kembali".9899Ini sangat berguna ketika Anda tidak menggunakan `fetch`. Banyak aplikasi membaca data dari Prisma, Gerimis, SDK internal, klien CMS, atau fungsi layanan. Dalam kasus tersebut, alasan lama yang hanya didasarkan pada opsi `fetch` tidaklah cukup.100101Aturan praktisnya:102103- konten cachea relatif stabil;104- gunakan tag granular;105- meninggalkan izin dinamis, sesi, keranjang, pemberitahuan, dan status transaksional;106- masukkan bagian yang lambat ke dalam `Suspense`;107- mengukur sebelum mengatakan "kami meningkatkan kinerja".108109## Batalkan tanpa membuang semuanya110111Cache hanya berguna jika Anda dapat memperbaruinya secara akurat. Di sini `cacheTag`, `revalidateTag` dan `updateTag` menjadi penting.112113Contoh: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```129130Detail penting adalah tagnya. `product:${productId}` memberi tahu batasan yang tepat. `products` menceritakan sebuah ember besar. Pada awalnya ember besar itu terasa nyaman; setelah beberapa bulan itu menjadi alasan Anda membatalkan setengah aplikasi untuk mengubah judul.131132## Turbopack Stabil: bagian yang Anda dengar setiap hari133134Next.js 16 menghadirkan Turbopack ke pusat pengembangan dan pembangunan. Ini bukan fitur yang paling puitis, tapi itulah yang Anda rasakan saat bekerja: server yang dimulai lebih awal, penyegaran lebih cepat, build yang berhenti terasa seperti rehat kopi yang dipaksakan.135136Meskipun demikian, saya tidak akan memigrasikan basis kode yang penuh dengan plugin khusus dengan mata tertutup. Saya akan memeriksa:137138- bangunan lokal;139- impor nonstandar;140- MDX, SVG dan CSS;141- Plugin Webpack tersisa;142- halaman penting;143- perbedaan waktu pembuatan.144145Untuk proyek baru, saya akan memulai dari default. Untuk yang sudah dewasa, saya akan melakukan migrasi terukur.146147## React Compiler: menghilangkan kebisingan, bukan pikiran148149React Compiler 1.0 stabil dan Next.js 16 mendukungnya dengan `reactCompiler`. Janjinya adalah untuk mengurangi banyak memoisasi manual: lebih sedikit `memo`, lebih sedikit `useMemo`, lebih sedikit `useCallback` digunakan "untuk keamanan".150151```typescript152// next.config.ts153import type { NextConfig } from 'next';154155const nextConfig: NextConfig = {156 reactCompiler: true,157};158159export default nextConfig;160```161162Saya tidak akan memperlakukannya seperti debu ajaib. Kompiler membantu ketika kode mengikuti aturan React dengan baik. Jika komponen memiliki efek samping yang aneh, mutasi tersembunyi, atau kaitan yang digunakan secara buruk, hal ini perlu diperbaiki terlebih dahulu.163164Cara sehat untuk mencobanya:1651661. perbarui `eslint-plugin-react-hooks`;1672. memperbaiki pelanggaran yang sebenarnya;1683. aktifkan di area yang terkendali;1694. mengukur waktu dan perilaku pembangunan;1705. hapus memoisasi manual hanya jika tidak lagi diperlukan.171172Tujuannya bukan untuk menghapus setiap `useMemo`. Tujuannya adalah berhenti menulis memoisasi preventif karena takut rendering.173174## `proxy.ts` dan batas jaringan175176`middleware.ts` yang lama menjadi `proxy.ts`. Ini adalah perubahan nama, tetapi masuk akal: file itu berada di batas permintaan, ini bukan middleware generik bergaya backend tradisional.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```192193Aturannya di sini sederhana: jaga agar tetap kecil. Pengalihan, perutean autentikasi, header, penulisan ulang penting. Jika mulai terasa seperti backend kedua, mungkin fungsinya terlalu banyak.194195## Bagaimana saya benar-benar akan bermigrasi196197Saya tidak akan mengaktifkan semua fitur sekaligus. Saya akan melakukan ini:1981991. Saya memperbarui Berikutnya, Bereaksi dan Bereaksi DOM;2002. Saya meluncurkan codemod resmi;2013. Saya memperbaiki perubahan yang mengganggu pada `params`, `searchParams`, `cookies()`, `headers()` dan `draftMode()`;2024. Saya memigrasikan `middleware.ts` ke `proxy.ts`;2035. Saya memeriksa bangunan dan halaman penting;2046. Saya mengaktifkan Komponen Cache di bagian tempat cache saat ini menimbulkan gesekan;2057. Saya mendefinisikan konvensi untuk tag dan pembatalan;2068. Saya mencoba React Compiler secara terpisah;2079. perbandingan metrik sebelum dan sesudah.208209Migrasi yang baik bukanlah yang menggunakan semua fitur baru. Hal inilah yang membuat perilaku aplikasi lebih mudah dibaca.210211## Apa yang mengubah cara berpikir212213Hal yang paling berguna tentang Next.js 16 adalah memaksa Anda menyebutkan niat dengan lebih baik. Suatu fungsi bukan sekedar "mendapatkan produk dari database". Ini adalah "dapatkan produknya, saya dapat menyimpannya dalam cache selama berjam-jam, saya membatalkannya dengan tag ini". Sebuah komponen bukan sekedar "render halaman". Itu adalah "ini cangkang cepatnya, bagian ini bersifat pribadi, ini datang secara streaming."214215Pada awalnya sepertinya lebih banyak pekerjaan. Kemudian menjadi suatu bentuk ketenangan. Keputusan kinerja tidak lagi tersembunyi dalam kombinasi default, heuristik, dan memori suku. Mereka ada di dalam kode.216217## Sumber yang bermanfaat218219- [Catatan rilis Next.js 16](https://nextjs.org/blog/next-16)220- [Komponen Cache - Dokumen Next.js](https://nextjs.org/docs/app/getting-started/cache-components)221- [gunakan cache - dokumen Next.js](https://nextjs.org/docs/app/api-reference/directives/use-cache)222- [Kompiler Bereaksi v1.0](https://react.dev/blog/2025/10/07/react-compiler-1)223
:Next.js 16, Komponen Cache dan React Compiler: apa yang sebenarnya berubahlines 1-223 (END) — press q to close