Node.js bukan hanya runtime untuk server, melainkan juga lingkungan yang pas untuk skrip baris perintah yang membaca berkas, mengolah isinya, dan menulis hasilnya. Topik ini membangun satu skrip CLI (command line interface) yang benar-benar berjalan, yaitu penghitung kata yang merangkum sebuah berkas teks. Tiga modul inti diperkenalkan sepanjang pembahasannya, yaitu objek process untuk argumen dan kode keluar, node:fs untuk membaca berkas, dan node:path untuk mengolah jalurnya. Semua contohnya berjalan dengan Node.js tanpa package tambahan, dan pada akhirnya skrip yang sama dapat dipakai untuk menghitung berkas apa pun dari terminal.
Objek process: argumen dan kode keluar#
Objek process tersedia di seluruh program Node.js dan membawa informasi lingkungan tempat program itu berjalan. Properti process.argv berupa array yang merekam perintah yang diketik, dengan dua entri pertama selalu terisi, yaitu jalur biner node dan jalur berkas skripnya, sedangkan argumen milik pembaca skrip baru dimulai dari indeks 2. Kebiasaan yang aman adalah mengambil potongan itu lewat process.argv.slice(2) sehingga program tidak bergantung pada posisi entri bawaan.
// tidak-dijalankan
console.log(process.argv[0]); // jalur biner node
console.log(process.argv[1]); // jalur berkas skrip yang sedang berjalan
console.log(process.argv.slice(2)); // argumen yang diketik setelah nama skrip
Selain argumen, process.exit() mengakhiri proses seketika dengan kode keluar (exit code) yang diberikan. Kode 0 berarti program berakhir dengan sukses, sedangkan kode bukan nol menandakan kegagalan, dan kode inilah yang dibaca perangkat otomatis seperti CI (continuous integration) untuk memutuskan langkah berikutnya. Skrip yang mengembalikan kode keluar dengan benar jauh lebih mudah digabungkan ke dalam rangkaian perintah di terminal, karena program lain di sekitarnya dapat mengandalkan makna kode tersebut.
Membaca berkas dengan node:fs dan node:path#
Modul node:fs menangani berkas, dan untuk skrip CLI kecil bentuk sinkronnya paling ringkas, yaitu readFileSync(jalur, "utf8") yang menunggu sampai isi berkas terbaca, lalu mengembalikan string. Argumen "utf8" perlu diingat, karena tanpa itu fungsi yang sama mengembalikan objek Buffer, yaitu deretan byte mentah yang belum siap diolah sebagai teks. Sepasangannya adalah writeFileSync(jalur, isi) untuk menulis hasil ke berkas, sehingga satu skrip bisa membaca masukan sekaligus menyimpan keluaran tanpa package apa pun.
Modul node:path melengkapi keduanya dengan pengolahan jalur berkas lintas sistem operasi. Fungsi path.join() menggabungkan potongan jalur dengan pemisah yang benar, sedangkan path.basename() mengambil nama berkasnya saja dari sebuah jalur lengkap. Menyusun jalur lewat path.join("data", "catatan.txt") lebih aman daripada merangkai string secara manual, karena pemisah jalur berbeda antara Windows dan sistem berbasis Unix, sedangkan fungsi path selalu memilih yang tepat untuk sistem tempatnya berjalan.
Skrip CLI penghitung kata#
Skrip berikut menggabungkan ketiga modul itu menjadi alat yang berfungsi penuh, yaitu menghitung baris dan kata pada sebuah berkas teks. Susunannya mengikuti kebiasaan skrip CLI yang baik, argumen diperiksa lebih dahulu sebelum pekerjaan apa pun, lalu pekerjaan utama dibungkus try-catch agar error pembacaan berkas berubah menjadi pesan yang jelas dan kode keluar bukan nol. Dijalankan tanpa argumen, skrip menunjukkan cara pakainya dan berakhir dengan kode keluar 1.
// Penghitung kata CLI: membaca satu berkas teks dan merangkum isinya.
import { readFileSync } from "node:fs";
import { basename } from "node:path";
const berkas = process.argv[2];
if (!berkas) {
console.error("Cara pakai: node hitung-kata.mjs <berkas-teks>");
process.exit(1);
}
try {
const isi = readFileSync(berkas, "utf8");
const baris = isi.split("\n").filter((b) => b.trim() !== "").length;
const kata = isi.split(/\s+/).filter(Boolean).length;
console.log(`${basename(berkas)}: ${baris} baris, ${kata} kata`);
} catch (err) {
console.error(`Gagal membaca ${berkas}: ${err.message}`);
process.exit(1);
}Cara pakai: node hitung-kata.mjs <berkas-teks>Pemilihan console.error untuk pesan cara pakai bukan sekadar gaya. Pesan error dan petunjuk pemakaian secara lazim ditulis ke standard error agar terpisah dari keluaran data, sehingga keluaran normal skrip tetap dapat disalurkan ke berkas atau program lain tanpa tercampur pesan yang bukan datanya. Pola kecil inilah yang membedakan skrip seadanya dari alat baris perintah yang nyaman digabungkan dengan perintah lain.
Menjalankan skrip dari terminal#
Skrip hitung-kata.mjs diletakkan di folder kerja, sedangkan contoh berkas teks yang akan dihitung disiapkan terlebih dahulu di folder /tmp, folder sementara yang aman untuk latihan. Isinya jadwal piket kelas sepanjang enam baris, lalu skrip dijalankan dengan nama berkas itu sebagai argumennya.
# menyiapkan contoh berkas teks untuk dihitung
rm -rf /tmp/uji-cli
mkdir -p /tmp/uji-cli
printf 'Jadwal piket kelas 8B\nSenin: Ali menyapu lantai\nSelasa: Budi merapikan meja perpustakaan\nRabu: Citra menyiram tanaman\nKamis: Dewi mencatat daftar hadir\nJumat: piket bersama menata kursi\n' > /tmp/uji-cli/piket.txt
# menjalankan penghitung kata terhadap berkas tersebut
node hitung-kata.mjs /tmp/uji-cli/piket.txtpiket.txt: 6 baris, 27 kataKeluarannya singkat dan mudah dibaca ulang. Nama berkas diambil lewat path.basename() sehingga jalur /tmp/uji-cli/ tidak ikut tercetak, sedangkan jumlah kata didapat dengan memecah isi berkas pada setiap ruang kosong lalu menghitung potongan yang tidak kosong. Perilaku saat berkas yang diminta tidak ada juga sudah tertangani sejak skrip ditulis, seperti percobaan berikut.
# mencoba membaca berkas yang tidak ada
node hitung-kata.mjs /tmp/uji-cli/hilang.txtGagal membaca /tmp/uji-cli/hilang.txt: ENOENT: no such file or directory, open '/tmp/uji-cli/hilang.txt'Pesan error itu berasal dari objek err yang ditangkap blok catch, lengkap dengan kode ENOENT yang menandakan berkas tidak ditemukan. Skrip menyampaikan penyebabnya dengan jelas, tetapi berakhir rapi dengan kode keluar 1, bukan menampilkan tumpukan error mentah ke layar. Perbaikan yang wajar untuk langkah berikutnya adalah menerima lebih dari satu berkas sekaligus dengan process.argv.slice(2), lalu merangkum semuanya dalam satu laporan, pola yang sama dengan perintah wc pada sistem Unix.
Kesalahan umum#
Tiga kekeliruan berikut paling sering muncul saat skrip CLI pertama dibuat, dan semuanya cepat dikenali dari gejalanya.
- Lupa argumen
"utf8"padareadFileSync. Hasilnya bukan string melainkanBuffer, sehingga metode string sepertisplitmelempar error. Tambahkan argumen enkode pada setiap pembacaan teks. - Membaca argumen dari indeks yang salah, misalnya
process.argv[1]yang isinya justru jalur skripnya sendiri. Argumen milik pembaca selalu dimulai dari indeks 2. - Mengasumsikan jalur relatif selalu benar. Jalur relatif diurai dari direktori kerja tempat perintah dijalankan, bukan dari lokasi berkas skripnya, sehingga skrip yang dipanggil dari folder lain bisa gagal membaca berkas pendampingnya. Gunakan
path.joinbersamaimport.meta.dirnamebila jalurnya harus melekat pada lokasi skrip.
Kekeliruan ketiga punya gejala yang khas, yaitu error berkas tidak ditemukan padahal berkasnya terlihat ada. Ketika itu terjadi, cetak process.cwd() selama proses debugging untuk melihat direktori kerja yang sedang dipakai, lalu bandingkan dengan jalur yang dituju skrip. Kebiasaan menyebut jalur secara lengkap lewat node:path menghilangkan hampir semua kasus semacam ini.
Ringkasan#
process.argvmembawa argumen baris perintah mulai indeks 2, sedangkanprocess.exit()menetapkan kode keluar program.readFileSync(jalur, "utf8")membaca berkas sebagai teks,writeFileSyncmenulisnya kembali, dannode:pathmengolah jalur lintas sistem operasi.- Skrip CLI yang baik memeriksa argumen lebih dahulu, menangkap error pembacaan berkas dengan try-catch, dan menulis pesan error ke
console.error. - Kode keluar 0 berarti sukses, sedangkan kode bukan nol menandakan kegagalan yang dapat dibaca perangkat otomatis seperti CI.
Referensi#
- process — Node.js
— dokumentasi objek process, termasuk
argv,exit, dan kode keluar. - File system — Node.js — dokumentasi modul fs untuk membaca dan menulis berkas.
- path — Node.js — dokumentasi pengolahan jalur berkas lintas sistem operasi.