Upgrade Next.js dari v13 ke v14 Pengalaman nyata waktu nge-fix error build setelah migration
Ngomongin upgrade di dunia development, rasanya pasti campur aduk. Ada rasa semangat karena fitur baru, tapi juga ada ketakutan mendalam: "Apakah nanti proyekku bakal pecah semua?" Nah, kali ini, kami mau bagi-bagi pengalaman nyata, real-life scenario, saat harus memindahkan salah satu flagship project kami dari Next.js v13 ke v14.
Kenapa harus migrasi? Next.js 14 hadir bukan hanya sekadar minor update, tapi menegaskan kematangan ekosistem App Router, stabilitas Server Actions, dan tentu saja, peningkatan performa bundling berkat Turbopack yang makin matang. Bagi kami di Javapixa Creative Studio, menggunakan teknologi paling mutakhir adalah standar, demi memastikan klien mendapatkan performa dan keamanan terbaik. Tapi ya itu, prosesnya nggak selalu mulus.
Meskipun Next.js mengklaim migrasi v13 ke v14 relatif halus karena v14 adalah finalisasi dari fitur-fitur yang sudah ada di v13.4, realitas di lapangan selalu berbeda, terutama untuk proyek yang sudah berjalan lama dan punya banyak library pihak ketiga yang agak "nakal".
Berikut adalah drama dan solusi konkret yang kami temukan saat nge-fix error build setelah migrasi, lengkap dengan tips yang aplikatif.
---
Langkah Awal yang Menggoda (The Pre-Game)
Langkah pertama tentu saja update dependency. Kami menjalankan perintah keramat:
bash
npm install next@latest react@latest react-dom@latestSetelah dependency terinstal, saatnya next dev. Dan ajaibnya, project berjalan! Tidak ada error besar di console. Hati kami mulai berbunga. "Ah, sepertinya ini bakal gampang," pikir kami.
Kesalahan terbesar developer adalah merasa aman setelah next dev sukses. Realita pahit datang saat kami menjalankan:
bash
npm run buildBoom! Layar terminal langsung dipenuhi traceback merah yang panjangnya minta ampun. next dev itu penuh maaf, tapi next build versi produksi adalah hakim yang kejam, terutama dalam menegakkan aturan App Router yang ketat.
---
Fokus Masalah 1: App Router dan Batasan use client yang Lebih Ketat
Next.js 14 memaksa proyek untuk benar-benar mematuhi prinsip Server Components secara default. Meskipun kami sudah menggunakan App Router sejak v13, beberapa komponen lama, atau komponen yang di-import dari library pihak ketiga, ternyata masih melanggar batasan ini.
Error Inti: "Cannot access X outside of Client Components"
Kami sering melihat error ini menunjuk pada penggunaan hooks seperti useState, useEffect, atau bahkan usePathname (dari next/navigation) di file yang seharusnya sudah menjadi Client Component, tapi lupa diberi direktif use client.
Tips Aplikatif (The Strict Boundary Fix):
- Auditing Global Imports: Cari library UI (seperti beberapa versi headless UI atau utility library yang belum sepenuhnya Next.js 14-ready) yang di-import di layout utama (misalnya
layout.tsxdi root). Ingat, layout utama seharusnya selalu Server Component. Jika layout Anda harus meng-import sesuatu yang bergantung pada context browser (misalnya Provider untuk state management atau theme switching yang perlu akseslocalStorage), pastikan logika tersebut dibungkus rapat dalam wrapper atau Provider terpisah yang diberiuse client. - Mengisolasi Hooks: Kami menemukan kasus di mana sebuah Server Component (SC) meng-import komponen utilitas (UC) yang tidak punya
use client, tapi UC itu meng-import hook browser. Solusinya: Jangan pernah biarkan SC meng-import sesuatu yang secara transitif bergantung pada hooks browser. Pindahkan hook tersebut ke komponen anak yang spesifik dan eksplisit diberiuse clientdi baris paling atas. - Kasus
next/navigation: Di v14, penggunaanusePathname,useSearchParams, atauuseRouterharus 100% berada di file denganuse client. Jika Anda butuh Pathname di Server Component, ambil dari props atau header (misalnya menggunakanheaders()darinext/headers). Jangan paksakan hook navigasi di SC.
---
Fokus Masalah 2: Metadata API dan Static Generation
Next.js 14 sangat menekankan pada Static Generation (SG) secara default jika memungkinkan, terutama untuk metadata. Cara lama mendefinisikan metadata dengan generateMetadata seringkali memicu error build jika fungsi tersebut secara tidak sengaja mencoba mengakses data yang hanya tersedia saat runtime (dynamic data).
Error Inti: "Hydration failed because the initial UI does not match what was rendered on the server."
Ini adalah error klasik, tapi setelah migrasi, frekuensinya meningkat karena Next.js 14 lebih agresif dalam pra-rendering metadata.
Tips Aplikatif (Metadata & Dynamic Data):
- Pemisahan Data Statis dan Dinamis: Jika
generateMetadataAnda mengakses data yang berubah-ubah (misalnya mengambil data dari API eksternal yang tidak di-cache), Anda perlu memastikan bahwa page atau layout tersebut juga secara eksplisit diatur sebagai Dynamic Rendering.
Solusi Cepat: Tambahkan export const dynamic = 'force-dynamic'; di file yang bermasalah. Ini akan memberitahu Next.js untuk tidak mencoba cache* atau melakukan SG pada halaman tersebut.
- Metadata Asynchronous: Pastikan fungsi
generateMetadataAnda benar-benar await data yang dibutuhkan, dan data tersebut tidak bergantung pada cookies atau headers yang hanya ada saat request individual, kecuali jika Anda memang ingin halaman tersebut menjadi Dynamic. - Menggunakan
viewportdanthemeColor: Next.js 14 mempromosikan konfigurasi viewport dan themeColor melalui ekspor konfigurasi baru di dalam layout atau page. Pindahkan konfigurasi ini dari tag manual di ke konfigurasi standarexport const viewport = {}atauexport const metadata = {}. Ini mencegah konflik saat Next.js melakukan server-side rendering metadata.
---
Fokus Masalah 3: Server Actions dan Form Data
Salah satu breaking change yang paling halus namun mematikan adalah handling data form dan bindings dalam Server Actions. Meskipun Server Actions distabilkan di v14, ada perubahan kecil pada parsing data.
Error Inti: Type Mismatch saat Menggunakan FormData
Kami menggunakan Server Actions untuk form submission. Di v13, kami bisa agak santai dalam menerima FormData. Di v14, type checking jadi lebih ketat, terutama jika Anda menggunakan TypeScript.
Tips Aplikatif (Server Actions Hygiene):
- Validasi Eksplisit dengan
zod: Jika Anda belum menggunakan validation library seperti Zod untuk Server Actions, sekaranglah waktunya. Next.js 14 bekerja lebih baik dengan skema data yang terstruktur. Pastikan data yang masuk ke Server Action divalidasi dan di-parsed sebelum diproses lebih lanjut. - Binding Argumen: Jika Anda menggunakan
binduntuk meneruskan ID atau argumen tambahan ke Server Action, pastikan argumen tersebut di-serialize dengan benar. Beberapa library (terutama yang berinteraksi dengan forms non-standar) mungkin memiliki masalah serialization yang baru muncul dinext build. - Lokasi Server Action: Pastikan Server Action didefinisikan di file terpisah (
actions.ts) atau langsung di Server Component. Mendefinisikannya di Client Component (meskipun ini dimungkinkan) bisa menimbulkan kebingungan build jika import jalur file-nya tidak bersih.
---
Fokus Masalah 4: Cache dan Revalidate (The Old vs. New Cache API)
Proyek kami memanfaatkan caching bawaan Next.js 13 (terutama fetch caching dan revalidatePath). Di v14, API ini distabilkan dan sedikit dimodifikasi cara kerjanya di bawah kap mesin, khususnya bagaimana revalidatePath berinteraksi dengan segment yang nested dalam App Router.
Error Inti: Invalidate Cache Gagal atau Data Stale di Production
Meskipun bukan error build yang memecahkan kode, ini adalah error logistik yang sering luput: data stale di lingkungan produksi setelah deployment.
Tips Aplikatif (Cache Integrity):
- Lupakan
unstablecache:Jika Anda pernah menggunakan API eksperimental sepertiunstablecachedi v13, segera migrasikan ke APIcacheyang distabilkan (yang sebenarnya adalah wrapper untukfetchAPI standar). revalidatePathvs.revalidateTag: Next.js 14 cenderung lebih menyukairevalidateTag. Jika Anda menggunakanrevalidatePath('/user/[id]'), pastikan Next.js benar-benar bisa memetakan path tersebut ke segment yang tepat. Jika terasa tidak efektif, beralihlah ke penandaan data Anda menggunakanfetch(URL, { next: { tags: ['my-tag'] } })dan panggilrevalidateTag('my-tag')di Server Action. Ini jauh lebih eksplisit dan andal di v14.- Pengaruh
force-dynamic: Jika Anda menetapkanexport const dynamic = 'force-dynamic'di suatu halaman, semua fetch di halaman tersebut akan diabaikan oleh caching bawaan Next.js. Pastikan Anda hanya menggunakan ini jika benar-benar diperlukan. Terlalu banyak menggunakan force-dynamic akan menghapus manfaat performa dari SG.
---
Kesimpulan: Kualitas Kode Adalah Kunci
Proses migrasi dari Next.js v13 ke v14 ini, meskipun menguras energi, adalah pengingat penting: Next.js makin ketat dalam menegakkan aturan best practice React (Server Components). Error build yang muncul bukanlah kebetulan; mereka menunjukkan di mana batasan antara kode sisi klien dan sisi server Anda masih kabur.
Total ada sekitar 40-an error build yang harus kami debug satu per satu, dan hampir 90% di antaranya terkait dengan dua hal: missing use client atau misplaced hook di Server Component.
Bagi tim Javapixa Creative Studio, pengalaman ini menegaskan komitmen kami. Kami percaya bahwa setiap investasi waktu dalam menjaga codebase tetap bersih dan mengikuti standar Next.js terbaru akan membuahkan hasil dalam bentuk performa yang superior dan maintainability yang lebih mudah.
Jika Anda berencana migrasi atau membangun aplikasi Next.js baru dan ingin menghindari sakit kepala ini dari awal, ingatlah filosofi Next.js 14: Default adalah Server Component. Jadilah eksplisit tentang apa yang Anda ingin render di klien. Ketika Anda sudah memahaminya, semua error ini akan terasa seperti petunjuk, bukan penghalang. Dan ya, setelah semua fix diterapkan, waktu build kami memang jauh lebih cepat, dan itu sepadan dengan semua drama traceback merah itu.