path.join() menggabungkan segmen path dengan separator yang benar dan merapikan .. serta slash ganda, tetapi tetap membiarkan hasilnya relatif kalau kamu mulai dengan segmen relatif. path.resolve() melakukan pekerjaan yang sama dari kanan ke kiri dan selalu mengembalikan path absolut: ia mulai dari current working directory, dan segmen absolut mana pun di tengah jalan memulai ulang path-nya. Pakai join untuk menyusun path, dan resolve saat kamu butuh path absolut.
Hasilnya users/ada/notes.txt, lalu users/grace/todo.txt (.. menghapus ada), lalu /srv/app/public/index.html dan src/lib/utils.js: slash berlebih dan segmen kosong hilang. join tidak pernah menganggap /public/ sebagai awal yang baru; itu hanya segmen berikutnya.
path.join vs path.resolve
Perbedaannya terlihat saat sebuah segmen diawali / atau saat segmen pertama relatif:
Dengan /public di tengah, join menghasilkan /srv/app/public/img, sedangkan resolve membuang semua yang ada sebelumnya dan menghasilkan /public/img; keduanya menangani .. dengan cara yang sama. Dua baris terakhir menunjukkan bahwa join membiarkan public/index.html tetap relatif, sedangkan resolve membuatnya absolut dengan menaruh folder saat ini di depannya.
path.join | path.resolve | |
|---|---|---|
| Hasil | Relatif atau absolut, mengikuti input | Selalu absolut |
Segmen yang diawali / | Hanya segmen biasa | Memulai ulang path di situ |
| Titik awal | Tidak ada | Current working directory |
| Tanpa argumen | '.' | Current working directory |
| Penggunaan umum | Menyusun path dari beberapa bagian | Mengubah input user atau config menjadi path absolut |
basename, dirname, extname dan parse
Fungsi-fungsi ini membongkar sebuah path. Mereka hanya melihat string-nya: file-nya tidak harus ada.
Hasilnya cat.final.jpg, cat.final, /home/ada/photos, dan .jpg: extname hanya mengambil bagian setelah titik terakhir. path.parse mengembalikan semuanya sekaligus (root, dir, base, ext, name), dan path.format mengubah object seperti itu kembali menjadi string.
__dirname dan __filename
Di file CommonJS, __dirname adalah path absolut dari folder yang berisi file itu, dan __filename adalah file itu sendiri. Path relatif seperti 'data.json' relatif terhadap tempat user menjalankan node, dan langsung rusak begitu ada yang menjalankan script-mu dari folder lain. Susun path dari __dirname saja:
Hasilnya config.json dark dan index.js. Path lengkapnya berbeda di setiap mesin, dan justru karena itu kamu menyusunnya dengan path.join(__dirname, ...), bukan mengetiknya.
__dirname di ES module: import.meta.dirname
ES module tidak punya __dirname; memakainya melempar ReferenceError: __dirname is not defined in ES module scope. Sejak Node.js 20.11, import.meta.dirname dan import.meta.filename menggantikannya:
Hasilnya index.js dan data/users.json. Di versi Node.js sebelum 20.11, ambil foldernya dari URL module: path.dirname(fileURLToPath(import.meta.url)), dengan fileURLToPath dari node:url.
Kenapa tidak menggabungkan path dengan string
'data' + '/' + file bekerja di macOS dan Linux, lalu gagal di Windows, yang separator-nya \, dan tidak menangani .., slash ganda, atau slash yang hilang. path memakai aturan sistem tempat ia berjalan. Kamu bisa melihat hasil versi Windows dari mesin mana pun dengan path.win32:
const path = require('path');
path.posix.join('users', 'ada', 'notes.txt'); // 'users/ada/notes.txt'
path.win32.join('users', 'ada', 'notes.txt'); // 'users\\ada\\notes.txt'
path.sep; // '/' on macOS and Linux, '\\' on Windows
Berikan hasil path.join ke fs.readFile dan kode yang sama membaca file-nya di setiap sistem.
Kesalahan umum
Mengira extname paham ekstensi ganda. path.extname('archive.tar.gz') bernilai '.gz', dan dotfile seperti .env tidak punya ekstensi sama sekali: path.extname('.env') bernilai ''. Cek sendiri akhiran namanya saat seluruh akhiran itu penting.
Mengandalkan join untuk menjaga user tetap di dalam folder. path.join('/srv/app', '../../etc/passwd') bernilai '/etc/passwd'. Sebelum membaca file yang namanya berasal dari request, resolve path-nya dan cek bahwa path itu masih diawali folder milikmu.
Pertanyaan yang sering diajukan
Apa bedanya __dirname dan process.cwd()?
__dirname adalah folder dari file source saat ini dan tidak pernah berubah. process.cwd() adalah folder tempat user menjalankan node. Keduanya sama hanya saat program dijalankan dari foldernya sendiri.
Sebaiknya pakai path.join atau path.resolve dengan __dirname?
Keduanya bisa untuk path.join(__dirname, 'data.json'), karena __dirname sudah absolut. Pakai resolve saat sebuah segmen mungkin juga absolut, seperti path yang diketik user, dan kamu ingin path itu yang menang.
Bagaimana memakai module path untuk URL?
Jangan: URL selalu memakai / dan punya aturan sendiri untuk .. dan query string. Pakai class URL, seperti new URL('../img/logo.png', 'https://example.com/docs/page').