Skip to content

Satu Direktif yang Menandai Seluruh Modul, Bukan Cuma Komponen

Adityo Guni Waluyo

Impor fungsi bantu dari file bertanda modul klien menghasilkan referensi, bukan fungsi. Error runtime dan pola modul netralnya.

Ringkasan

Error "is not a function" muncul di halaman /budaya. Fungsi toVideoItems tidak bisa dipanggil dari server karena diekspor dari modul klien. Modul netral tanpa direktif bisa menyelesaikan masalah ini.

Dari mana error itu datang

Salam 500 pertama muncul di halaman /budaya, sebuah pilar situs portal kota fiktif KotaPortal. Stack trace-nya satu baris yang membingungkan: toVideoItems is not a function. Anehnya, fungsi itu ada. File-nya ada. Path impor tidak salah ketik, dan di halaman lain yang mengimpor modul yang sama lewat komponen klien, semuanya jalan normal.

Tebakan pertama salah arah. Kecurigaan jatuh ke isi fungsi toVideoItems: mungkin ada refactor yang menghapus eksportnya, atau mapper-nya salah referensi. Semua skenario itu tidak ketemu. Fungsi diekspor dengan benar dari video-playlist.tsx, lengkap dengan tipenya EntityVideoItem.

Satu-satunya yang berbeda dari pemakaian lain: halaman /budaya adalah Server Component, dan ia memanggil toVideoItems langsung saat render server. Fungsi bantu biasa itu diekspor dari file yang paling atasnya ada penanda modul klien.

Gejala semacam ini enak dikenali setelah kejadian, tapi sulit ditebak saat pertama. Pesan error menunjuk ke pemanggil, bukan ke file sumbernya. Compiler TypeScript juga diam: dari sudut pandang tipenya, impor lintas file itu sah, karena yang menjadi masalah bukan tipe melainkan tempat kode dievaluasi. Build produksi pun lolos sampai halaman benar-benar dirender, sehingga kejadian, sempat mengira masalahnya di data yang dikirim API.

Direktifnya menandai modul, bukan komponen

Anggapan awal yang keliru: direktif itu hanya melabeli komponen interaktif di dalam file, sisanya (tipe, konstanta, fungsi bantu) tetap netral. Kenyataannya direktif bekerja di level modul. Seluruh isi file dan semua yang diimpornya masuk grafik modul klien. Pada dokumentasi Next.js tentang batas server dan klien [1], grafik yang terpisah itu dirender menjadi payload RSC: server menghasilkan referensi ke Client Component plus props yang bisa diserialkan, bukan nilai fungsi utuh.

Konsekuensinya, ekspor non-komponen dari modul klien tidak bisa dipanggil dari sisi server. Dokumen direktif tersebut di react.dev [2] merumuskannya tegas: nilai yang diimpor dari modul bertanda tersebut oleh kode server hanya boleh berupa komponen React atau nilai props yang bisa diserialkan; pemakaian lain melempar exception. Yang diterima halaman server bukan fungsi toVideoItems, melainkan referensi klien yang tidak bisa dipanggil. Error "is not a function" hanyalah bentuk gejala di permukaan.

Yang bikin sulit dideteksi: modul yang sama bisa jalan normal di satu tempat dan gagal di tempat lain. Satu modul dievaluasi di server ketika diimpor kode server, dan dievaluasi di klien ketika diimpor kode klien. Jadi yang menentukan bukan isi file, melainkan dari grafik mana file itu diimpor. Halaman lain yang mengimpor modul itu lewat jalur klien tidak akan pernah melihat error ini.

Perbaikan: modul netral tanpa direktif

Solusinya bukan mengubah isi mapper, melainkan alamatnya. EntityVideoItem dan toVideoItems pindah ke video-items.ts, file TypeScript polos tanpa direktif apa pun.

// Sebelum: util numpang di modul "use client"
import { toVideoItems } from "./video-playlist"; // gagal saat dipanggil dari server

// Sesudah: modul netral, aman dipanggil kedua grafik
import { toVideoItems } from "./video-items";

Modul tanpa direktif bisa dievaluasi di kedua grafik, jadi halaman pilar server memanggil fungsi bantunya langsung, dan VideoPlaylist di sisi klien mengimpor tipe dari tempat yang sama tanpa duplikasi. Setelah pertukaran impor ini, build dan rangkaian test komponen kembali hijau; tidak ada satu baris pun isi mapper yang berubah.

Pola ini mempersempit dampak direktif ke tempat semestinya. Dokumen referensi direktif di Next.js [3] mengingatkan, direktif hanya perlu ada di file yang dirender langsung oleh Server Component, bukan di semua file yang berisi komponen klien. Aturan praktis yang tersisa: mapper, tipe, dan konstanta yang dipakai lintas grafik tinggal di modul netral; penanda klien hanya di komponen entry yang memang butuh state atau event handler. Kekeliruan berikutnya jadi lebih cepat terdeteksi. Kalau error "is not a function" muncul lagi, cek dulu dari grafik mana fungsi itu dipanggil, sebelum mencurigai isinya.

Sumber

  1. Next.js Docs, The Server and Client Boundary, diakses 26 Oktober 2026.
  2. react.dev, halaman referensi direktif, diakses 26 Oktober 2026.
  3. Next.js Docs, referensi direktif, diakses 26 Oktober 2026.

Artikel terkait