module.exports adalah nilai yang diberikan sebuah file Node.js kepada file lain yang memuatnya dengan require(). Nilainya berawal dari object kosong: tambahkan property padanya untuk meng-export beberapa hal, atau isi dengan nilai baru (fungsi, class) untuk meng-export satu hal. exports adalah variabel singkat yang menunjuk ke object yang sama, jadi exports.add = ... bekerja, tetapi exports = ... memutus hubungannya dan tidak meng-export apa pun.
Hasilnya 5 20 3.14159, lalu [ 'add', 'multiply', 'PI' ]. Ketiga baris di math.js menambahkan property ke object yang sama, entah lewat module.exports atau exports, dan require('./math') mengembalikan object itu.
Export fungsi, class, atau object
Saat sebuah module punya satu hal utama, isikan langsung ke module.exports. Pemanggil lalu mendapat fungsinya sendiri, bukan object yang membungkusnya:
Hasilnya Hello, Ada dan Grace (user). Kalau kamu melihat TypeError: greet is not a function, pemanggil memakai bentuk yang salah: tulis const { greet } = require(...) untuk property object dan const greet = require(...) untuk nilai yang diisikan langsung.
module.exports vs exports: jebakan mengisi ulang
Sebelum file-mu berjalan, Node.js menetapkan exports = module.exports. Kedua nama menunjuk ke satu object, dan require mengembalikan module.exports. Mengisi nilai baru ke exports hanya mengubah variabel lokalnya:
broken.js meng-export {}, karena exports sekarang menunjuk ke object baru yang tidak dikembalikan oleh siapa pun. working.js meng-export { version: 2 }.
| Kamu menulis | Ter-export? |
|---|---|
module.exports.x = 1 | Ya |
exports.x = 1 | Ya, object yang sama |
module.exports = { x: 1 } | Ya, menggantikan object-nya |
exports = { x: 1 } | Tidak, nilainya hilang |
Aturan paling sederhana: selalu tulis module.exports. Cara ini bekerja di setiap kasus, dan kodenya menyatakan apa yang dilakukannya.
require mengembalikan object yang sama dari cache
Node.js menjalankan kode sebuah module sekali, saat pertama kali di-require, lalu menyimpan module.exports di cache. Setiap require berikutnya untuk file yang sama mengembalikan object yang sama, jadi state di dalam sebuah module dibagi oleh setiap file yang memuatnya:
counter.js is running muncul sekali, b.next() mengembalikan 3, dan a === b bernilai true, karena kunci cache-nya adalah path file yang sudah di-resolve, dan ./counter serta ./counter.js mengarah ke file yang sama. Itulah sebabnya koneksi database atau object konfigurasi yang dibuat di satu module dipakai bersama oleh seluruh aplikasi.
module.exports dan ES module
ES module memakai export dan import. Bentuk-bentuknya saling berpadanan seperti ini:
// CommonJS // ES modules
module.exports = greet; export default greet;
module.exports.add = add; export { add };
const greet = require('./greet'); import greet from './greet.js';
const { add } = require('./math'); import { add } from './math.js';
ES module bisa meng-import file CommonJS: module.exports miliknya datang sebagai default import. Sejak Node.js 22.12, require() juga bisa memuat ES module yang tidak punya top-level await. Untuk kapan memilih yang mana, lihat CommonJS vs ES modules.
Kesalahan umum
Mencampur exports.x dengan module.exports = ... dalam satu file. Pengisian itu menggantikan object-nya, jadi setiap exports.x yang ditulis sebelumnya hilang. Pilih satu gaya per file.
Meng-export nilai yang nanti berubah. module.exports = { count } menyalin angkanya saat dimuat; saat module memperbarui count, pemanggil tetap melihat nilai lama. Export fungsi yang mengembalikannya, seperti yang dilakukan counter.js di atas.
Lupa menulis ./. require('math') mencari package di node_modules, bukan math.js di samping file-mu. File lokal selalu diawali ./ atau ../.
Pertanyaan yang sering diajukan
Bisakah aku memakai module.exports dan export di file yang sama?
Tidak. Sebuah file adalah CommonJS (require, module.exports) atau ES module (import, export). Node.js menentukannya dari ekstensi (.cjs atau .mjs) atau dari "type" di package.json.
Kenapa require mengembalikan object kosong?
Biasanya module itu menulis exports = ... alih-alih module.exports = ..., atau dua module saling me-require. Dalam require yang melingkar, salah satunya menerima module.exports milik yang lain sebelum file itu selesai berjalan.
Apakah aku perlu ekstensi .js di require?
Tidak. require('./math') mencoba ./math, lalu ./math.js, ./math.json, dan ./math.node, lalu folder ./math yang berisi index.js. Di import milik ES module, ekstensinya wajib.
Bagaimana cara memuat ulang module yang sudah di-cache oleh require?
Hapus entrinya dengan delete require.cache[require.resolve('./math')] lalu require lagi. Ini terutama berguna di pengujian dan alat development; kode aplikasi sebaiknya tidak bergantung padanya.