Node.js datang dengan modul bawaan yang tinggal dipakai, tanpa npm install. Bayangin kamar kos yang sudah lengkap perabotnya: ada lemari untuk menyimpan barang, denah yang memberi alamat tiap ruangan, dan papan info gedung. Di Node, lemarinya fs (membaca dan menulis file), denahnya path (menyusun alamat file), dan papan infonya os (info tentang mesin).
🧪 Tebakan cepat:
__dirnameberisi/home/budi/catatan-api. File mana yang dibuka__dirname + "data/catatan.json"? Tebak dulu, jawabannya ada di bagian "path: menyusun alamat file".
Modul bawaan: tinggal require
const fs = require("node:fs/promises");
const path = require("node:path");
const os = require("node:os");
Awalan node: menandai modul bawaan Node. Tanpa awalan juga jalan (require("fs")), tapi dengan awalan langsung jelas ini bukan paket dari npm. node:fs/promises adalah versi fs yang mengembalikan Promise, jadi bisa dipakai dengan await.
fs: membaca file
Proyek catatan-api sekarang menyimpan datanya di file data/catatan.json, isinya array dua catatan yang sama dengan pelajaran sebelumnya. app.js membacanya:
async function main() {
const lokasi = path.join(__dirname, "data", "catatan.json");
console.log(lokasi);
try {
const isi = await fs.readFile(lokasi, "utf8");
const catatan = JSON.parse(isi);
console.log(catatan.length + " catatan dibaca");
} catch (err) {
console.log(err.message);
}
}
main();
$ node app.js
/home/budi/catatan-api/data/catatan.json
2 catatan dibaca
fs.readFile(lokasi, "utf8")membaca file dan mengembalikan isinya sebagai teks.awaitmenunggu hasilnya tanpa menghentikan pekerjaan lain di Node.JSON.parse(isi)mengubah teks itu jadi array.try { ... } catch (err) { ... }menangkap error. Kalau file-nya gak ada, isierr.messageadalahENOENT: no such file or directory, open '/home/budi/catatan-api/data/hilang.json', danerr.codeadalah"ENOENT"(Error NO ENTry, gak ada entri dengan nama itu).
Hampir tiap fungsi fs punya tiga gaya: Promise (await fs.readFile, yang dipakai di sini), callback (fs.readFile(lokasi, "utf8", (err, isi) => {...}), gaya lama), dan Sync (fs.readFileSync). Versi Sync memblokir event loop: selama file dibaca, Node gak bisa mengerjakan apa pun, termasuk menjawab request lain. Itu gak masalah di script sekali jalan atau saat server baru menyala, tapi jangan dipakai di dalam handler request.
path: menyusun alamat file
__dirname berisi folder tempat file yang sedang jalan berada. path.join menyambung bagian-bagian alamat dengan pemisah yang benar untuk OS-nya:
| Kode | Linux dan macOS | Windows |
|---|---|---|
path.join(__dirname, "data", "catatan.json") |
/home/budi/catatan-api/data/catatan.json |
C:\Users\budi\catatan-api\data\catatan.json |
__dirname + "/data/catatan.json" |
/home/budi/catatan-api/data/catatan.json |
C:\Users\budi\catatan-api/data/catatan.json |
__dirname + "data/catatan.json" |
/home/budi/catatan-apidata/catatan.json |
C:\Users\budi\catatan-apidata/catatan.json |
Baris terakhir menjawab tebakannya: __dirname gak diakhiri garis miring, jadi catatan-api dan data menempel jadi catatan-apidata. File itu gak ada, hasilnya ENOENT. Baris tengah jalan di Linux, tapi di Windows pemisahnya campur aduk: Node di Windows masih mau membukanya, tapi path seperti itu gak cross-platform dan gampang rusak waktu dibandingkan atau dikirim ke program lain. path.join memilih pemisah yang benar dan merapikan garis miring ganda, jadi pakai itu.
Fungsi path lain yang sering dipakai, untuk lokasi di atas:
path.extname(lokasi)→".json"path.basename(lokasi)→"catatan.json"path.dirname(lokasi)→"/home/budi/catatan-api/data"
os: info tentang mesin
console.log(os.platform()); // "linux", "darwin" (macOS), atau "win32" (Windows)
console.log(os.cpus().length); // jumlah core CPU, misalnya 8
console.log(os.homedir()); // "/home/budi"
os berguna untuk menyesuaikan program dengan mesinnya, misalnya memakai semua core CPU (nanti di pelajaran clustering).
Di ES Modules, __dirname gak ada
File ES Modules yang menulis __dirname gagal dengan ReferenceError: __dirname is not defined in ES module scope. Penggantinya import.meta.dirname (ada sejak Node 20.11), dan import.meta.filename untuk path file-nya sendiri.
Di latihan: fs tiruan
Simulator latihan gak punya disk sungguhan, jadi "file system"-nya object files yang memetakan nama file ke isinya. readFile(filepath) mengembalikan isinya, atau melempar error dengan throw new Error("File tidak ditemukan") kalau nama itu gak ada. transform(filepath) membacanya di dalam try, membesarkan hurufnya dengan toUpperCase(), mengambil ekstensinya dengan path.extname, lalu mencetak:
notes.txt -> ext: .txt, content: HELLO DUNIA
data.json -> ext: .json, content: {"X":1}
missing.txt -> Error: File tidak ditemukan
⚠️ Jebakan yang sering ketemu
readFileSyncdi dalam handler request. Semua request lain ikut menunggu sampai file selesai dibaca. Di handler, pakaiawait fs.readFile.- Lupa
"utf8". Tanpa encoding,readFilemengembalikan Buffer (deretan byte), danconsole.logmencetak<Buffer 5b 0a 20 20 7b ...>, bukan teksnya. - Menyambung path dengan
+. Garis miring yang hilang atau pemisah yang campur. Pakaipath.join. - Path relatif dari folder yang salah.
"data/catatan.json"dihitung dari folder tempat kamu menjalankannode, bukan dari folder file-nya. Jalan dari folder lain, hasilnyaENOENT.path.join(__dirname, ...)gak terpengaruh.
TL;DR: Modul bawaan dipakai tanpa install: require("node:fs/promises"), require("node:path"), require("node:os"). Baca file dengan await fs.readFile(lokasi, "utf8") di dalam try/catch, dan file yang gak ada memberi err.code "ENOENT". readFileSync memblokir event loop, jadi jangan dipakai di handler request. Susun alamat dengan path.join(__dirname, "data", "catatan.json"): pemisahnya / di Linux dan macOS, \ di Windows, sedangkan menyambung dengan + gak cross-platform. path.extname mengambil ekstensi, os.platform() memberi nama OS. Di ES Modules, pakai import.meta.dirname.