Manifes package.json di chapter sebelumnya hanya berupa daftar nama: "ms": "^2.1.3". Berkas library itu sendiri tidak ikut disalin saat proyek dikirim — dan memang tidak perlu, karena ukurannya bisa membengkak. Pertanyaannya, siapa yang mengunduh library tersebut, menempatkan berkasnya di folder yang benar, dan memastikan versi yang terpasang identik di mesin semua anggota tim?
Jawabannya npm, package manager yang terpasang bersama Node.js. Chapter ini menuntaskan siklus kerjanya di folder latihan: membuat manifes, memasang package, membaca node_modules dan package-lock.json, membedakan npm ci dari npm install, serta mengeksekusi package lewat npx yang selama ini kita pakai untuk ESLint dan Prettier. Semua keluaran di chapter ini direkam nyata dengan npm 11.19.0.
Membuat Manifes dengan npm init #
Folder latihan dimulai kosong. Perintah npm init membuatkan manifes pertama, dan opsi -y menerima semua nilai bawaan tanpa pertanyaan:
npm init -yOutput yang Dihasilkan:
Wrote to /home/z/my-project/scripts/npm-demo/package.json:
{
"name": "npm-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs"
}Beberapa hal di keluaran ini layak dicatat:
- Baris 1 (
Wrote to ...): nama folder otomatis menjadi nama package — folder latihan kita bernamanpm-demo. Field yang wajib (namedanversion) langsung terisi. - Bagian
scripts: npm mengisi scripttestdengan penanda temporer yang berhenti dengan pesan kesalahan. Kita menggantinya begitu test nyata tersedia. - Baris
"type": "commonjs": npm 11 menuliskan mode module secara eksplisit. Nilai ini menegaskan perilaku bawaan Node — berkas.jsdibaca sebagai CommonJS, sehingga contohrequire()di chapter ini sah tanpa berkas.mjs.
npm install: Mengisi node_modules #
Perintah inti npm adalah npm install <nama-package>. npm mengunduh package dari registry, menempatkannya di folder node_modules, dan mencatatnya ke manifes. Kita pasang satu package runtime dan satu package pengembangan:
npm install ms
npm install --save-dev picocolorsOutput yang Dihasilkan:
added 1 package, and audited 2 packages in 435ms
found 0 vulnerabilitiesKeluaran instalasi kedua (dengan --save-dev) nyaris sama: added 1 package, and audited 3 packages in 447ms. Arti tiap bagiannya:
added 1 package: npm menempatkan satu folder baru dinode_modules. Foldernode_moduleskini berisimsdanpicocolors—picocolorsdipilih sebagai contoh devDependency karena juga berukuran kecil (pewarna teks terminal).audited 2 packages: npm memeriksa package terpasang terhadap basis data advisory keamanan — mekanisme yang dibedah tuntas di chapter dependency-security pada section Security.found 0 vulnerabilities: hasil pemeriksaan tersebut, bersih pada contoh ini.
Angka milidetik pada keluaran npm — 435ms, 447ms, dan 410ms pada contoh chapter ini — adalah durasi pemasangan yang terekam di lingkungan uji kita; nilainya wajar berbeda di mesin lain. Yang harus selalu sama adalah jumlah package: added 1 package untuk satu package, dan audited menghitung seluruh package yang diperiksa sampai saat itu.
Sebagai bukti bahwa package benar-benar terpasang dan siap dipakai, berkas berikut memanggil ms:
// uji-paket.js — memakai package ms yang baru dipasang
const ms = require("ms");
console.log(ms("2 days"));
console.log(ms("1 h"));Output yang Dihasilkan:
172800000
3600000Perhatikan satu hal penting: kita tidak menulis require("./node_modules/ms"). Ketika bertemu require("ms"), Node mencari folder node_modules dari lokasi berkas ke atas, menemukan package itu, dan membaca titik masuknya. Dua angka keluaran adalah hasil konversi durasi: dua hari bernilai 172.800.000 milidetik dan satu jam bernilai 3.600.000 milidetik.
package-lock.json: Rekam Versi Persis #
Di manifes kita menulis rentang ^2.1.3, tetapi yang benar-benar terpasang hari ini adalah 2.1.3. Versi persis itu direkam npm di berkas package-lock.json — lockfile yang menyimpan seluruh pohon dependensi beserta sidik jarinya:
{
"name": "npm-demo",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "npm-demo",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"ms": "^2.1.3"
},
"devDependencies": {
"picocolors": "^1.1.1"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},"version": "2.1.3": versi persis yang terpasang — inilah yang membuat rentang^2.1.3menjadi konkrit."resolved": alamat unduhan tempat package diambil."integrity": hash SHA-512 dari isi package. Saat memasang ulang, npm menghitung hash hasil unduhan dan membandingkannya — isi package yang terjadi perubahan akan ditolak."dev": true(pada entripicocolors): penanda bahwa package ini bagian dari devDependencies.
Hubungan kedua berkas bisa diringkas begini: package.json mencatat keinginan (rentang yang ditulis manusia), sedangkan package-lock.json mencatat kenyataan (versi persis yang sudah teruji). Karena itu lockfile wajib ikut disimpan di repository — dua mesin yang menjalankan pemasangan dari lockfile yang sama mendapatkan pohon dependensi yang identik. Sebaliknya, node_modules tidak pernah ikut disimpan: isinya bisa dipulihkan kapan saja dari lockfile.
npm ci: Pemasangan yang Tepat Sesuai Lockfile #
Untuk pemasangan dari lockfile, npm menyediakan perintah khusus. Skenario berikut menghapus node_modules terlebih dahulu, lalu memasang ulang dengan npm ci:
rm -rf node_modules
npm ciOutput yang Dihasilkan:
added 2 packages, and audited 3 packages in 410ms
found 0 vulnerabilitiesHasilnya sama seperti npm install — dua package terpasang — tetapi kontrak keduanya berbeda:
| Aspek | npm install | npm ci |
|---|---|---|
| Sumber keputusan versi | Manifes, lalu lockfile | Lockfile saja |
| Memperbarui lockfile | Ya, bila manifes berubah | Tidak pernah |
Folder node_modules lama | Dipakai ulang sebagian | Dihapus lalu dipasang ulang |
| Manifes dan lockfile tak sinkron | Disesuaikan diam-diam | Berhenti dengan kesalahan |
| Cocok untuk | Pengembangan harian | CI dan penerapan otomatis |
Karena tegas dan dapat diprediksi, npm ci menjadi pilihan baku di lingkungan CI: setiap eksekusi pipeline memasang persis keadaan yang pernah teruji, tanpa kejutan versi baru.
npx: Menjalankan Package Tanpa Memasang #
Perintah terakhir menutup lingkaran dari chapter ESLint. npx mengeksekusi package sebagai program: bila package sudah ada di node_modules atau di cache npx, ia dipakai langsung; bila belum, npx mengunduhnya sementara. Versinya sama dengan npm:
npx --versionOutput yang Dihasilkan:
11.19.0Perintah npx --yes eslint@latest kode.js yang kita jalankan di chapter ESLint kini terbaca utuh: npx mengambil ESLint (dengan opsi --yes untuk melewati konfirmasi), menjalankannya satu kali, dan menyimpannya di cache untuk pemanggilan berikutnya. Untuk alat yang dipakai tim setiap hari, pemasangan resmi sebagai devDependencies tetap lebih tepat — versi terkunci, tersedia luring, dan tercatat di lockfile.
Kini seluruh kebutuhan proyek — kode, alat, dan versinya — tercatat dan terpasang secara terkontrol. Chapter berikutnya berpindah ke sisi lain dari aplikasi nyata: bagaimana kode yang sama membaca nilai yang berbeda di tiap lingkungan tempat ia dijalankan.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
uji-paket.js
Unduh berkas// uji-paket.js — memakai package ms yang baru dipasang
const ms = require("ms");
console.log(ms("2 days"));
console.log(ms("1 h"));