Pesan Error & Artinya

Ketika kamu bekerja dengan Node.js dan mencoba mengimpor pustaka Cheerio di proyek modern, kamu mungkin dihadapkan pada pesan error yang terlihat seperti ini:

SyntaxError: The requested module 'cheerio' does not provide an export named 'default'

Atau dalam beberapa lingkungan runtime, pesannya bisa muncul dalam format yang sedikit berbeda:

SyntaxError: Named export 'default' not found. The requested module 'cheerio' is a CommonJS module, which may not support all required EcmaScript module features.

Pesan error ini secara sederhana berarti bahwa kode kamu mencoba melakukan default import terhadap modul Cheerio menggunakan sintaks ESM (ECMAScript Modules), tetapi Cheerio — sebagai paket yang dipublikasikan dalam format CommonJS — tidak menyediakan ekspor bernama default. Dalam ekosistem Node.js, ada dua sistem modul yang berjalan berdampingan: CommonJS (yang menggunakan require() dan module.exports) dan ESM (yang menggunakan import dan export). Ketika kamu menulis import cheerio from 'cheerio', kamu meminta default export dari modul tersebut. Namun Cheerio mengekspor objeknya menggunakan module.exports, yang dalam konteks interop ESM-CJS tidak selalu dipetakan secara otomatis menjadi default export.

Error ini muncul paling sering ketika kamu menambahkan "type": "module" di package.json atau menggunakan ekstensi file .mjs, yang memberitahu Node.js untuk memperlakukan kode kamu sebagai ESM. Pada saat yang sama, Cheerio versi tertentu (terutama versi 1.0.0-rc.x) murni dikemas sebagai CommonJS tanpa ESM wrapper atau conditional exports yang memetakan default export. Node.js kemudian menolak melakukan interop otomatis karena dianggap ambigu dan berpotensi berbahaya — sehingga error ini dilempar ke permukaan.

Contoh kode yang memicu error:

// file: scraper.mjs
// atau file .js dengan "type": "module" di package.json

import cheerio from 'cheerio';  // ❌ Error di sini

const html = '<h2 class="title">Hello world</h2>';
const $ = cheerio.load(html);
console.log($('.title').text());

Penyebab Umum

Berikut adalah penyebab-penyebab paling umum yang membuat error ini muncul, diurutkan dari yang paling sering terjadi di lapangan:

  1. Menggunakan default import ESM terhadap paket CJS murni. Ini adalah penyebab nomor satu. Kamu menulis import cheerio from 'cheerio' di file ESM, tapi Cheerio di node_modules adalah paket CommonJS yang tidak punya export default. Node.js tidak bisa menebak apakah module.exports seharusnya diperlakukan sebagai default export atau sebagai namespace, jadi ia menolak dan melempar error.

  2. Versi Cheerio yang tidak kompatibel dengan ESM. Cheerio versi 1.0.0-rc.10 ke bawah sama sekali tidak menyertakan exports map di package.json-nya. Baru di versi 1.0.0-rc.12 dan yang lebih baru, maintainer Cheerio mulai menambahkan conditional exports yang secara eksplisit mendukung ESM. Jika kamu terjebak di versi lama, default import akan selalu gagal.

  3. Bundler atau transpiler yang mengubah perilaku interop. Tools seperti esbuild, Rollup, atau bahkan Babel dengan preset tertentu bisa menghasilkan kode interop yang berbeda-beda. esbuild, misalnya, secara default mengasumsikan CJS modules punya default export dan akan mensintesis satu. Tapi ketika kode dijalankan langsung di Node.js (tanpa bundler), asumsi itu tidak berlaku dan error muncul.

  4. Versi Node.js yang lebih ketat terhadap ESM-CJS interop. Mulai Node.js v16 dan lebih ketat lagi di v18+, perilaku default interop antara ESM dan CJS semakin strict. Versi Node yang lebih lama mungkin "memaafkan" impor ini, tapi versi baru tidak.

  5. Cache module yang basi. Kadang-kadang, setelah kamu mengubah konfigurasi atau meng-upgrade Cheerio, Node.js masih menggunakan versi cache yang lama dari modul resolution, sehingga error tetap muncul meskipun perbaikan sudah diterapkan.

Untuk memastikan penyebab mana yang kamu alami, jalankan diagnosa berikut:

  • Cek versi Cheerio: npm ls cheerio — jika di bawah 1.0.0-rc.12, itu kemungkinan besar penyebabnya.
  • Cek versi Node.js: node --version — jika di bawah v16, pertimbangkan upgrade.
  • Cek type di package.json: cat package.json | grep '"type"' — jika "type": "module" ada, kamu berada di mode ESM.
  • Cek isi ekspor Cheerio: node -e "console.log(Object.keys(require('cheerio')))" — ini menunjukkan apa yang sebenarnya diekspor.

Solusi Step-by-Step

Langkah 1: Ganti Default Import Menjadi Named Import atau Namespace Import

Cara paling langsung dan cepat adalah mengubah cara kamu mengimpor Cheerio. Alih-alih menggunakan default import, gunakan namespace import yang secara eksplisit menangkap seluruh module.exports sebagai objek:

// ❌ Sebelum (memicu error)
import cheerio from 'cheerio';

// ✅ Sesudah (namespace import)
import * as cheerio from 'cheerio';

Setelah diubah, kode lengkapnya menjadi:

import * as cheerio from 'cheerio';

const html = '<h2 class="title">Hello world</h2>';
const $ = cheerio.load(html);
console.log($('.title').text());  // Output: Hello world

Output yang diharapkan: Tidak ada error. Program berjalan normal dan mencetak "Hello world".

Verifikasi: Jalankan file dengan node scraper.mjs. Jika tidak ada error dan output sesuai, solusi ini berhasil.

Langkah 2: Upgrade Cheerio ke Versi yang Mendukung ESM

Jika kamu ingin tetap menggunakan sintaks import cheerio from 'cheerio' (default import), kamu perlu versi Cheerio yang secara native mendukung ESM:

npm install cheerio@latest

Atau jika kamu ingin versi spesifik yang sudah mendukung ESM:

npm install cheerio@1.0.0-rc.12

Output yang diharapkan:

added 1 package, changed 3 packages in 2s

Verifikasi: Setelah install, cek bahwa Cheerio sekarang punya exports map:

node -e "const pkg = require('cheerio/package.json'); console.log(pkg.exports)"

Jika output menunjukkan objek exports dengan kunci "import" dan "require", maka Cheerio versi baru sudah mendukung ESM dan default import seharusnya bisa digunakan.

Langkah 3: Bersihkan Cache Jika Error Masih Muncul

Kadang setelah upgrade, Node.js masih menggunakan resolusi modul yang lama dari cache:

# Hapus node_modules dan reinstall
rm -rf node_modules package-lock.json
npm install

Pada Windows (PowerShell):

Remove-Item -Recurse -Force node_modules, package-lock.json
npm install

Output yang diharapkan: Fresh install tanpa error, semua dependensi terresolve ulang.

Verifikasi: Jalankan kembali file yang bermasalah. Jika berhasil, masalahnya memang cache yang basi.

Langkah 4: Gunakan Dynamic Import sebagai Alternatif

Jika kamu berada di situasi di mana static import tetap bermasalah (misalnya karena constraint transpiler), dynamic import bisa menjadi jalan keluar yang reliable:

// dynamic-import-scraper.mjs
async function scrape() {
  const cheerio = await import('cheerio');
  const $ = cheerio.default 
    ? cheerio.default.load('<h2>Hello</h2>') 
    : cheerio.load('<h2>Hello</h2>');
  console.log($('h2').text());  // Output: Hello
}

scrape();

Pendekatan ini bekerja karena await import() mengembalikan objek namespace yang berisi seluruh named exports plus default jika tersedia. Dengan mengecek cheerio.default, kamu bisa menangani kedua skenario — baik saat Cheerio menyediakan default export maupun tidak.

Fix Permanen (Bukan Workaround)

Solusi-solusi di atas bersifat reaktif. Agar error ini tidak kembali muncul di masa depan, kamu perlu menerapkan konfigurasi dan best practice yang lebih fundamental.

Konfigurasi package.json dengan Exports Map

Jika kamu membangun pustaka sendiri yang menggunakan Cheerio secara internal, tambahkan exports map yang eksplisit di package.json kamu:

{
  "name": "my-scraper",
  "type": "module",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    }
  },
  "dependencies": {
    "cheerio": "^1.0.0-rc.12"
  }
}

Exports map memberitahu Node.js persis file mana yang harus diresolve untuk setiap kondisi impor, mengeliminasi ambiguitas yang menjadi akar masalah error ini.

Pin Versi Cheerio di package.json

Untuk mencegah regresi, pin versi Cheerio yang sudah terbukti mendukung ESM:

{
  "dependencies": {
    "cheerio": "1.0.0-rc.12"
  }
}

Hindari menggunakan ^ atau ~ jika kamu ingin benar-benar memastikan versi tidak bergeser ke versi yang berbeda perilaku. Meskipun dalam praktiknya, versi yang lebih baru dari 1.0.0-rc.12 seharusnya terus mendukung ESM.

Best Practice: Konsistensi Sistem Modul

Keputusan terbesar yang harus kamu buat di awal proyek adalah: apakah proyek ini ESM atau CJS? Jangan mencampur keduanya tanpa strategi yang jelas. Jika proyek kamu ESM:

  • Set "type": "module" di package.json.
  • Gunakan ekstensi .mjs untuk file ESM dan .cjs untuk file CJS yang tidak bisa dihindari.
  • Untuk setiap dependensi CJS, gunakan import * as pkg from 'pkg' bukan import pkg from 'pkg'.

Jika proyek kamu CJS:

  • Jangan set "type": "module".
  • Gunakan const cheerio = require('cheerio') dan tidak akan ada masalah.

Perbedaan Antar OS

Perbedaan OS biasanya tidak menjadi faktor utama untuk error ini, karena Node.js menangani ESM-CJS interop secara konsisten lintas platform. Namun, ada nuansa kecil:

  • Windows: Perintah rm -rf tidak tersedia di Command Prompt. Gunakan PowerShell dengan Remove-Item -Recurse -Force seperti ditunjukkan di Langkah 3. terus, path separator (\ vs /) kadang mempengaruhi bagaimana exports map di-resolve, terutama jika kamu menulis exports map manual dengan path yang salah.
  • macOS/Linux: Tidak ada issue spesifik. Semua perintah di artikel ini berjalan as-is.
# macOS/Linux: bersihkan cache
rm -rf node_modules/.cache

# Windows PowerShell: bersihkan cache
Remove-Item -Recurse -Force node_modules\.cache -ErrorAction SilentlyContinue

Troubleshooting Lanjutan

Jika semua solusi di atas sudah kamu coba dan error tetap muncul, ada beberapa kemungkinan yang lebih dalam yang perlu diselidiki.

Cek Apakah Ada Alias atau Resolution Override

Beberapa framework seperti Next.js, Nuxt, atau Vite melakukan module resolution k