Modul JavaScript: Memecah Kode Menjadi File yang Bisa Dipakai Ulang

ES module membuatmu bisa memecah satu skrip besar menjadi file-file kecil yang saling export dan import. Pelajari export, import, default vs named export, dan bagaimana modul menjaga kodemu tetap rapi tanpa mengotori global.

Diterbitkan 14 Agustus 202611 menit bacaOleh ACY Partner Indonesia
Modul JavaScript — export dan import antar file
300 × 250Slot Iklan TersediaPasang iklan Anda di sini

Untuk sementara waktu, kamu masih bisa menaruh seluruh proyek di dalam satu file .js. Cara ini jalan — sampai akhirnya nggak jalan lagi. Begitu file-nya melar melewati beberapa ratus baris, mencari apa pun di dalamnya jadi menyiksa, dua fungsi tanpa sengaja memakai nama variabel yang sama, dan tiap skrip baru yang kamu tambahkan ke halaman bisa diam-diam menabrak skrip lainnya karena semuanya hidup di ruang global yang sama. Modul adalah jawaban JavaScript untuk kekacauan itu: cara memecah kode ke banyak file, di mana tiap file menyatakan dengan jelas apa yang ia bagikan ke dunia luar (export) dan apa yang ia ambil dari tempat lain (import).

Kalau kamu pernah menulis JavaScript yang lumayan serius, kamu pasti pernah merasakan masalah yang dipecahkan oleh modul ini. Begitu kamu terbiasa dengan export dan import, kamu bakal ogah balik lagi ke satu file raksasa. Artikel ini membahas sistem ES module modern — standar yang sudah ada di semua browser terkini dan di Node.js — dari nol.

Apa itu modul, dan kenapa kamu butuh

Modul itu sederhananya cuma sebuah file JavaScript yang memakai export dan import. Itu saja definisinya. Begitu sebuah file ikut sistem ini, ada tiga hal berguna yang langsung terjadi:

  • Variabel di level atasnya jadi privat. Apa pun yang kamu deklarasikan di dalam modul hanya berlaku lokal di file itu, kecuali kamu export secara sengaja. Nggak ada lagi tabrakan global yang nggak disengaja.
  • Ketergantungan jadi terlihat jelas. Kamu bisa melihat di bagian atas file apa saja yang ia butuhkan, ketimbang cuma berharap ada tag <script> lain yang sudah termuat lebih dulu.
  • Kode jadi bisa dipakai ulang. Fungsi yang ditulis sekali di math.js bisa di-import ke sepuluh file lain tanpa salin-tempel.

Sebelum era modul, satu-satunya cara berbagi kode antar tag <script> adalah menumpuk semuanya ke objek global window lalu berdoa supaya tidak ada yang bentrok. Modul memensiunkan era itu sepenuhnya. Tiap file punya scope-nya sendiri yang bersih — erat kaitannya dengan konsep scope dan closure yang mungkin sudah kamu pelajari — dan kamu menyambungkan antar file secara sengaja.

Named export

Cara paling umum untuk berbagi sesuatu adalah lewat named export. Kamu tinggal menempelkan kata kunci export di depan sebuah deklarasi, lalu nama yang kamu pakai itulah yang dipakai file lain untuk meng-import-nya.

Misalkan kamu punya satu file berisi fungsi-fungsi bantu:

// math.js
export const PI = 3.14159;

export function add(a, b) {
  return a + b;
}

export function multiply(a, b) {
  return a * b;
}

Sekarang ada tiga hal yang di-export dari math.js: sebuah konstanta PI, dan dua fungsi add serta multiply. Apa pun lainnya yang mungkin kamu tulis di file itu (variabel bantu, fungsi internal) tetap tinggal privat di sana.

Di file lain, kamu meng-import-nya berdasarkan nama, di dalam kurung kurawal:

// app.js
import { add, multiply, PI } from "./math.js";

console.log(add(2, 3));        // 5
console.log(multiply(4, 5));   // 20
console.log(PI);               // 3.14159

Path "./math.js" itu adalah path relatif — tanda ./ berarti “di folder yang sama dengan file ini.” Nama-nama di dalam { } harus sama persis dengan nama yang di-export, karena dari situlah kedua file sepakat soal apa yang sedang dibagikan.

Kamu nggak harus meng-import semua yang ditawarkan sebuah modul. Ambil saja yang kamu butuhkan:

import { add } from "./math.js";   // multiply dan PI tidak pernah ikut termuat ke file ini

Export inline atau sekaligus di akhir

Kamu bisa menulis export langsung di depan tiap deklarasi seperti di atas, atau mendaftar semuanya dalam satu pernyataan di bagian bawah file: export { add, multiply, PI };. Keduanya menghasilkan named export yang sama persis — pilih mana yang lebih enak dibaca untuk file itu. Daftar di bagian bawah file praktis dipakai kalau kamu mau punya satu tempat untuk melihat sekaligus semua yang dikeluarkan sebuah modul.

Mengganti nama dengan as

Kadang nama yang di-import bakal bentrok dengan sesuatu yang sudah kamu punya, atau namanya memang jadi kurang jelas di konteks yang baru. Pakai as untuk mengganti namanya saat di-import:

import { add as sum } from "./math.js";

console.log(sum(10, 20));   // 30

Kamu juga bisa mengganti nama di sisi export, tapi mengganti nama saat import inilah yang paling sering kamu pakai. Kata kunci as yang sama juga memungkinkan satu trik praktis — menarik semua export dari sebuah modul ke dalam satu objek namespace:

import * as math from "./math.js";

console.log(math.add(2, 3));   // 5
console.log(math.PI);          // 3.14159

Sekarang math adalah objek yang propertinya berisi setiap named export tadi. Ini bikin rapi kalau sebuah modul meng-export banyak hal dan kamu malas mendaftar satu per satu — meski mendaftar nama biasanya tetap lebih jelas buat yang membaca kode.

Default export

Sebuah modul juga bisa punya satu default export — yaitu satu hal “utama” yang benar-benar jadi inti dari file itu. Kamu menandainya dengan export default:

// User.js
export default function createUser(name) {
  return { name, createdAt: Date.now() };
}

Saat meng-import default, kamu tidak memakai kurung kurawal, dan — ini bedanya yang penting — kamu sendiri yang menentukan namanya:

import createUser from "./User.js";
// atau, sama-sama sah:
import makeUser from "./User.js";

const u = createUser("John Doe");

Karena default hanya ada satu per file, file yang meng-import bebas menamainya sesuai selera. Sebuah file boleh mencampur satu default export dengan beberapa named export, dan kamu meng-import kedua gaya itu dalam satu baris:

// User.js
export default function createUser(name) { /* ... */ }
export const ROLES = ["admin", "editor", "viewer"];
import createUser, { ROLES } from "./User.js";

Default ditulis duluan (tanpa kurung kurawal), baru kemudian named export di dalam kurung kurawal.

Default vs named: tentukan satu kebiasaan dan konsisten

Default dan named export gampang ketuker. Aturannya begini: satu file boleh punya paling banyak satu default export, tapi named export-nya boleh berapa pun. Kamu meng-import default tanpa kurung kurawal dan dengan nama bebas; kamu meng-import named export di dalam kurung kurawal dengan nama persisnya. Mencampuradukkan keduanya — menaruh named import di luar kurung kurawal, atau default di dalamnya — adalah salah satu error modul yang paling sering terjadi. Banyak tim memilih aturan seperti “satu hal utama per file → default; kumpulan fungsi bantu → named” lalu menerapkannya konsisten supaya pola import-nya gampang ditebak.

Bagaimana browser memuat modul

Tag <script> biasa tidak mengerti import dan export. Supaya sebuah modul bisa jalan di browser, kamu menandai skripnya dengan type="module":

<script type="module" src="app.js"></script>

Satu atribut ini sekaligus mengubah beberapa perilaku, dan semuanya penting buat kamu tahu:

  • Browser akan mengikuti pernyataan import di dalam app.js, mengambil tiap ketergantungannya, lalu menjalankannya dengan urutan yang benar. Kamu cukup menunjuk ke file utama (entry) saja.
  • Skrip modul otomatis ditunda (deferred) — ia menunggu sampai HTML selesai diparsing baru dijalankan, jadi kamu nggak perlu menaruhnya di bagian bawah <body> atau membungkus kodenya dengan listener load.
  • Tiap modul otomatis berjalan dalam strict mode, dan variabel di level atasnya tidak ikut menempel ke window global.

Ada satu jebakan praktis yang perlu kuingatkan sejak awal.

Modul butuh server, bukan protokol file://

Kalau kamu membuka file HTML ber-type="module" dengan cara klik dua kali (sehingga di address bar muncul file://...), import-nya bakal gagal dengan error CORS. Browser menolak memuat modul lewat protokol file:// karena alasan keamanan. Solusinya, sajikan file-nya lewat HTTP — jalankan dev server lokal apa saja (misalnya npx serve, ekstensi editor “Live Server”, atau perintah dev dari framework-mu) lalu buka halamannya di http://localhost/.... Hampir semua orang kepleset di sini saat pertama kali, dan pesan error-nya jarang menjelaskan penyebabnya dengan gamblang.

Contoh nyata dengan banyak file

Coba kita rangkai sesuatu yang lebih dekat dengan dunia nyata: keranjang belanja kecil, dipecah dengan rapi ke beberapa file. Pertama, beberapa fungsi bantu:

// format.js
export function formatHarga(jumlah) {
  return "Rp " + jumlah.toLocaleString("id-ID");
}
// cart.js
export function hitungTotal(items) {
  return items.reduce((total, item) => total + item.harga * item.jumlah, 0);
}

Sekarang sebuah file utama yang menarik keduanya dan memakainya bareng:

// app.js
import { hitungTotal } from "./cart.js";
import { formatHarga } from "./format.js";

const items = [
  { nama: "Keyboard", harga: 250000, jumlah: 1 },
  { nama: "Mouse", harga: 120000, jumlah: 2 },
];

const total = hitungTotal(items);
console.log(formatHarga(total));   // "Rp 490.000"

Tiap file mengerjakan satu tugas: format.js memformat uang, cart.js mengurus hitungan keranjang, app.js menyatukan keduanya. Kalau ada bug di angka total, kamu langsung tahu file mana yang harus dibuka. Kejelasan seperti inilah inti dari modul — dan manfaatnya makin terasa tiap kali kamu menambah file baru. Pemanggilan reduce di sini adalah salah satu metode array yang sebaiknya kamu kuasai secara terpisah.

Modul vs sistem lama (CommonJS)

Cepat atau lambat kamu bakal ketemu sintaks lain di tutorial-tutorial lama dan di kode Node.js: require() dan module.exports. Itu CommonJS, sistem modul yang dipakai Node.js sebelum ES module jadi standar.

// CommonJS — gaya LAMA, kebanyakan di kode Node.js lawas
const math = require("./math.js");
module.exports = { add, multiply };

Untuk kode baru, lebih baik pakai ES module — yaitu sintaks import/export di artikel ini. Itu standar resmi bahasanya, jalan secara native di browser, dan Node.js versi modern sudah mendukungnya penuh (cukup set "type": "module" di package.json, atau pakai ekstensi .mjs). Tahu bahwa CommonJS itu ada tetap berguna buat membaca kode lama, tapi biasanya kamu nggak akan memakainya lagi saat memulai sesuatu yang baru sekarang.

Cara cepat membedakan keduanya

Kalau kamu melihat import / export, itu ES module — standar modern. Kalau kamu melihat require() / module.exports, itu CommonJS — kebiasaan lama di Node.js. Keduanya tidak sepenuhnya bisa saling tukar, dan mencampurnya dalam satu proyek bisa memunculkan error yang membingungkan, jadi ada baiknya kamu tahu dulu yang mana yang sedang dipakai sebuah file (atau proyek) sebelum mulai mengedit.

Dynamic import

Semua yang dibahas sejauh ini sifatnya statis — import yang ditulis di bagian atas file, dan diselesaikan sebelum modulnya jalan. Kadang kamu ingin memuat sebuah modul hanya saat benar-benar dibutuhkan — misalnya library grafik yang berat tapi cuma dipakai di satu halaman. Untuk itu ada fungsi import(), yang mengembalikan sebuah promise:

button.addEventListener("click", async () => {
  const { drawChart } = await import("./chart.js");
  drawChart();
});

Di sini chart.js baru diunduh saat pengguna benar-benar mengeklik tombolnya. Inilah dasar dari code splitting — mengirim JavaScript lebih sedikit di awal lalu memuat sisanya sesuai kebutuhan. Kamu nggak akan butuh ini di hari pertama, tapi enak buat tahu bahwa pintunya ada, apalagi untuk aplikasi besar yang waktu muatnya penting.

Praktik terbaik

Beberapa kebiasaan yang bikin basis kode berbasis modul tetap enak dikerjakan:

  • Satu tanggung jawab per file. Sebuah modul sebaiknya hanya soal satu hal yang jelas. Kalau kamu nggak bisa merangkum tugas sebuah file dalam satu frasa pendek, kemungkinan ia memikul terlalu banyak.
  • Export dengan sengaja. Export hanya yang benar-benar dibutuhkan file lain. Sisanya tetap privat — privasi itu fitur, bukan keterbatasan.
  • Pakai path yang jelas dan konsisten. Path relatif (./, ../) menjelaskan dengan gamblang di mana sebuah file berada. Konsistenlah supaya import-nya gampang dibaca sekilas.
  • Jangan terlalu memecah-mecah. Modul itu bagus, tapi seratus file berisi sepuluh baris bisa sama sulitnya dijelajahi seperti satu file raksasa. Kelompokkan kode yang berkaitan dengan masuk akal.
  • Hindari import melingkar. Kalau a.js meng-import dari b.js dan b.js balik meng-import dari a.js, kamu bisa mendapat nilai undefined saat file dimuat. Ini biasanya pertanda ada kode bersama yang sebaiknya dipindah ke file ketiga yang bisa di-import oleh keduanya.

Penutup

Modul menyulap skrip yang berantakan jadi sekumpulan file yang rapi dan bisa dipakai ulang:

  • Modul adalah file .js yang memakai export untuk berbagi sesuatu dan import untuk menariknya masuk. Variabel di level atasnya secara default tetap privat.
  • Named export di-import di dalam { } memakai nama persisnya; ganti namanya dengan as, atau tarik semuanya sekaligus dengan import * as nama.
  • Sebuah file boleh punya satu default export (export default), yang di-import tanpa kurung kurawal dan dengan nama bebas pilihanmu. Kamu boleh mencampur satu default dengan beberapa named export di file yang sama.
  • Di browser, muat modul dengan <script type="module">, dan sajikan lewat HTTPfile:// nggak akan jalan.
  • Untuk kode baru, lebih baik pakai ES module (import/export) ketimbang CommonJS lawas (require/module.exports). Pakai import() dinamis kalau kamu ingin memuat modul sesuai kebutuhan.

Setelah kodemu terbagi rapi ke beberapa file, langkah berikutnya yang wajar adalah merapikan data dan perilaku di dalam file-file itu menjadi cetak biru yang bisa dipakai ulang. Itu tugas class — yang jadi bahasan artikel berikutnya — dan kebetulan pas banget dipadukan dengan sistem modul yang baru saja kamu pelajari di sini.

Tag:javascriptfrontendmodulimportexportmenengah
728 × 90Slot Iklan TersediaPasang iklan Anda di sini

Artikel Terkait

Lihat Semua Artikel

Artikel yang Mungkin Kamu Suka

Apa Itu Framework Frontend? — chip kode dengan tag komponen
Frontend / Dasar

Apa Itu Framework Frontend?

Penjelasan ramah untuk pemula tentang apa itu framework frontend, kenapa mereka ada, masalah apa yang mereka selesaikan dibanding JavaScript biasa, dan kapan kamu memang sebaiknya memakainya.

20 Sep 20268 menit baca
Sampul fundamentals frontend bertuliskan Apa Itu Frontend dan HTML + CSS + JS
Frontend / Dasar

Apa Itu Frontend Development?

Panduan ramah pemula tentang frontend development: bagian website yang kamu lihat dan klik secara langsung. Pahami cara kerja HTML, CSS, dan JavaScript, serta bedanya frontend dengan backend.

20 Sep 20268 menit baca
Ilustrasi sampul untuk Apa yang Dikerjakan Frontend Developer
Frontend / Dasar

Apa yang Dikerjakan Frontend Developer: Panduan untuk Pemula

Penjelasan ramah pemula tentang apa yang sebenarnya dikerjakan frontend developer setiap hari: mengubah desain jadi antarmuka yang berfungsi, membangun UI yang bisa dipakai ulang, sampai urusan responsif, aksesibilitas, dan kecepatan.

20 Sep 20269 menit baca
Kartu judul bertuliskan Styling dan Interaktivitas di atas latar biru gelap ACY Partner
Frontend / Dasar

Cara Kerja Styling dan Interaktivitas

Penjelasan ramah pemula soal bagaimana CSS menyulap HTML polos jadi tampilan rapi, dan bagaimana JavaScript menambahkan perilaku — pola berpikir struktur, gaya, perilaku saat membangun halaman web.

20 Sep 20268 menit baca
Tiga lapisan front-end menyatu di satu halaman web
Frontend / Dasar

Cara HTML, CSS, dan JavaScript Bekerja Bersama

Panduan praktis untuk pemula: bikin satu tombol kecil, beri struktur dengan HTML, tampilan dengan CSS, dan perilaku dengan JavaScript, lalu lihat ketiga lapisan ini bekerja sama di halaman nyata.

20 Sep 20268 menit baca
Sampul ikhtisar praktik terbaik frontend
Frontend / Dasar

Ikhtisar Praktik Terbaik Frontend

Peta ringkas tentang apa itu frontend yang baik — HTML bermakna, CSS rapi, JavaScript secukupnya, desain responsif, performa, dan progressive enhancement, lengkap dengan arahan untuk mendalaminya.

20 Sep 20268 menit baca