npx dan skrip

Menjalankan CLI lewat npx, skrip proyek, dan variabel lingkungan pada skrip npm.

Daftar isi

npx dan npm run adalah dua cara utama menjalankan perintah dalam proyek Node.js. npx memanggil CLI dari paket tanpa harus memasangnya secara global, sedangkan npm run memanggil skrip yang dideklarasikan pada package.json. Topik ini membahas keduanya beserta variabel lingkungan yang tersedia saat skrip dijalankan. Setelah membaca topik ini, skrip proyek dapat disusun agar konfigurasi dapat diubah tanpa mengubah kode.

Menjalankan CLI dengan npx#

npx mencari perintah pada beberapa lokasi secara berurutan: direktori node_modules/.bin lokal, lalu PATH sistem, dan terakhir registry npm. Bila perintah tidak ditemukan secara lokal, npx mengunduh paket sementara dan menjalankannya tanpa memasangnya secara permanen. Perilaku ini berguna untuk perintah yang hanya dipakai sekali, misalnya scaffold (alat pembangkit kerangka proyek) atau formatter (alat pemformat kode) yang dijalankan pada pipeline CI.

Untuk paket lokal yang mendefinisikan bidang bin pada package.json, npx <nama> menjalankan CLI dari paket lokal tanpa unduhan. Berkas berikut mendefinisikan kalkulator baris perintah hitung yang membaca tiga argumen: angka, operator, dan angka.

js hitung.js
#!/usr/bin/env node
const [a, op, b] = process.argv.slice(2);

if (!a || !op || !b) {
  console.log('hitung: kalkulator baris perintah sederhana');
  console.log('pemakaian: hitung <a> <op> <b>');
  console.log('operator yang didukung: + - * /');
  process.exit(0);
}

const x = Number(a);
const y = Number(b);
switch (op) {
  case '+': console.log(x + y); break;
  case '-': console.log(x - y); break;
  case '*': console.log(x * y); break;
  case '/': console.log(x / y); break;
  default: console.error('operator tidak dikenal:', op); process.exit(1);
}
text Keluaran
hitung: kalkulator baris perintah sederhana
pemakaian: hitung <a> <op> <b>
operator yang didukung: + - * /

Baris #!/usr/bin/env node adalah shebang yang memberi tahu sistem operasi bahwa berkas ini dijalankan dengan Node. Bidang bin pada package.json berikut memetakan nama hitung ke berkas tersebut, sehingga npx hitung dapat menemukan dan menjalankannya dari paket lokal.

bash
# siapkan direktori demo di /tmp
rm -rf /tmp/npx-demo
mkdir /tmp/npx-demo
cp hitung.js /tmp/npx-demo/
chmod +x /tmp/npx-demo/hitung.js
(cd /tmp/npx-demo && cat > package.json <<'EOF'
{
  "name": "demo-hitung",
  "version": "1.0.0",
  "bin": {
    "hitung": "./hitung.js"
  }
}
EOF
npx hitung 2 + 3
npx hitung 12 - 5
npx hitung 6 '*' 7)
text Keluaran
5
7
42

Argumen '*' diberi tanda kutip agar shell tidak memperluasnya menjadi daftar berkas. Tanpa tanda kutip, karakter * akan digantikan oleh shell dengan nama berkas di direktori kerja, sehingga operator yang diterima hitung bukan lagi *.

Skrip npm dan lifecycle#

Bidang scripts pada package.json mendaftarkan perintah yang dapat dipanggil dengan npm run <nama>. Setiap entri adalah pasangan nama dan perintah shell yang dijalankan npm di dalam direktori paket. Skrip yang namanya diawali pre dan post dijalankan sebelum dan sesudah skrip utama dengan nama yang sama, sehingga pretest dijalankan sebelum test dan posttest setelahnya. Selain pasangan pre*/post*, terdapat nama lifecycle khusus lain yang dijalankan npm pada titik tertentu, yaitu install, postinstall, prepare, start, stop, restart, dan publish.

Skrip prepare dijalankan setelah npm install lokal maupun sebelum paket dipublikasikan ke registry. Pola ini lazim dipakai untuk membangun berkas distribusi dari sumber, misalnya mengompilasi TypeScript ke JavaScript atau menjalankan bundler. Skrip prepublishOnly dijalankan hanya sebelum publikasi, sehingga cocok untuk pemeriksaan akhir yang tidak perlu pada instalasi lokal.

Berikut adalah sapa-env.js, sebuah skrip yang membaca variabel lingkungan NAMA dan PORT, lalu mencetak salam.

js sapa-env.js
const nama = process.env.NAMA || 'Node';
const port = process.env.PORT || '3000';
console.log(`Halo, ${nama}!`);
console.log(`Server akan mendengarkan port ${port}.`);
text Keluaran
Halo, Node!
Server akan mendengarkan port 3000.

Variabel lingkungan pada skrip#

Variabel lingkungan diteruskan dari shell ke proses yang dijalankan npm run. Variabel yang ditulis sebelum perintah (pola KEY=value perintah) hanya berlaku untuk perintah tersebut, sedangkan variabel yang diekspor dengan export KEY=value bertahan untuk seluruh sesi shell. Pada sistem Unix, pola prefiks adalah cara standar menetapkan variabel sementara tanpa memengaruhi shell pemanggil.

bash
# siapkan direktori demo di /tmp
rm -rf /tmp/skrip-env-demo
mkdir /tmp/skrip-env-demo
cp sapa-env.js show-npm-env.js /tmp/skrip-env-demo/
(cd /tmp/skrip-env-demo && cat > package.json <<'EOF'
{
  "name": "demo-skrip-env",
  "version": "1.0.0",
  "scripts": {
    "sapa": "node sapa-env.js",
    "sapa-ali": "NAMA=Ali node sapa-env.js",
    "sapa-port": "NAMA=Budi PORT=8080 node sapa-env.js"
  }
}
EOF
npm run sapa
npm run sapa-ali
npm run sapa-port)
text Keluaran

> [email protected] sapa
> node sapa-env.js

Halo, Node!
Server akan mendengarkan port 3000.

> [email protected] sapa-ali
> NAMA=Ali node sapa-env.js

Halo, Ali!
Server akan mendengarkan port 3000.

> [email protected] sapa-port
> NAMA=Budi PORT=8080 node sapa-env.js

Halo, Budi!
Server akan mendengarkan port 8080.

Selain variabel dari shell, npm menyuntikkan beberapa variabel sendiri saat menjalankan skrip. Variabel npm_lifecycle_event berisi nama skrip yang sedang berjalan, npm_package_name dan npm_package_version berisi metadata dari package.json, dan npm_config_* berisi nilai konfigurasi npm. Berkas show-npm-env.js berikut membaca sebagian variabel tersebut.

js show-npm-env.js
// tidak-dijalankan secara mandiri: variabel npm_* hanya terisi saat dipanggil via npm run
console.log('npm_lifecycle_event:', process.env.npm_lifecycle_event);
console.log('npm_package_name:', process.env.npm_package_name);
console.log('npm_package_version:', process.env.npm_package_version);

Variabel npm_* hanya terisi ketika berkas dipanggil sebagai skrip npm, bukan saat dijalankan langsung dengan node show-npm-env.js. Demo berikut mendaftarkan show-npm-env.js sebagai skrip info-npm pada package.json, lalu menjalankannya dengan npm run info-npm.

bash
# tambah skrip info-npm dan jalankan
(cd /tmp/skrip-env-demo && node -e "const fs=require('fs'); const p=JSON.parse(fs.readFileSync('./package.json')); p.scripts['info-npm']='node show-npm-env.js'; fs.writeFileSync('./package.json', JSON.stringify(p,null,2))" && npm run info-npm)
text Keluaran

> [email protected] info-npm
> node show-npm-env.js

npm_lifecycle_event: info-npm
npm_package_name: demo-skrip-env
npm_package_version: 1.0.0

Nilai npm_lifecycle_event berubah mengikuti nama skrip yang dipanggil, sehingga skrip dapat menyesuaikan perilaku berdasarkan konteks pemanggilan.

Kesalahan umum#

Pemakaian npx <pkg> tanpa --no-install pada pipeline CI dapat memicu unduhan paket dari registry setiap kali pipeline berjalan. Unduhan ini menyebabkan pipeline tidak deterministik dan bergantung pada ketersediaan registry. Pasang paket secara lokal dan pakai npx --no-install untuk reproducibility.

Penulisan variabel lingkungan dengan export KEY=value di dalam skrip npm tidak memengaruhi skrip lain, karena setiap skrip dijalankan pada subshell terpisah. Untuk berbagi variabel antar-skrip, gunakan berkas .env yang dibaca saat runtime, atau tetapkan variabel pada level shell pemanggil.

Pemakaian tanda kutip yang salah pada argumen * dan -- sering menyebabkan argumen diabaikan shell. Bila sebuah argumen dimulai dengan -, gunakan -- sebagai pemisah agar npm tidak meneruskannya sebagai flag. Untuk operator *, beri tanda kutip agar shell tidak memperluasnya.

Ringkasan#

  • npx <nama> menjalankan CLI dari node_modules/.bin lokal, dari PATH, atau dari registry sebagai unduhan sementara.
  • Bidang bin pada package.json memetakan nama perintah ke berkas CLI, yang dipanggil oleh npx tanpa unduhan.
  • Skrip npm dipanggil dengan npm run <nama> dan mewarisi variabel lingkungan dari shell pemanggil, serta menerima variabel tambahan dari npm seperti npm_lifecycle_event dan npm_package_*.
  • Variabel lingkungan sementara dapat ditetapkan dengan pola prefiks KEY=value perintah, yang menjadi jembatan antara konfigurasi proses dengan kode yang membaca process.env.

Referensi#