Apa perbedaan antara __dirname dan ./ dalam node.js?

498

Ketika memprogram dalam Node.js dan mereferensikan file yang terletak di suatu tempat dalam kaitannya dengan direktori Anda saat ini, apakah ada alasan untuk menggunakan __dirnamevariabel bukan hanya biasa ./? Saya telah menggunakan ./ Sejauh ini dalam kode saya dan baru saja menemukan keberadaan __dirname, dan pada dasarnya ingin tahu apakah akan pintar untuk mengkonversi ./ saya untuk itu, dan jika demikian, mengapa itu akan menjadi ide yang cerdas .

iniissami
sumber
47
tl; dr: Jadi, pada dasarnya, perbedaannya adalah bahwa './' dan 'process.cwd ()' merujuk pada direktori saat ini dari terminal yang memanggil skrip, sedangkan '__dirname' merujuk pada direktori di mana skrip berada disimpan.
Gui Imamura
1
Kecuali saat .digunakan di dalam require. Jalur di dalam requireselalu relatif terhadap file yang berisi panggilan require.
Govind Rai

Jawaban:

814

Intinya

Di Node.js, __dirnameselalu direktori di mana skrip yang saat ini menjalankan berada ( lihat ini ). Jadi, jika Anda mengetik __dirnameke dalam /d1/d2/myscript.js, nilai akan /d1/d2.

Sebaliknya, .memberi Anda direktori dari mana Anda menjalankan nodeperintah di jendela terminal Anda (yaitu direktori kerja Anda) ketika Anda menggunakan perpustakaan seperti pathdan fs. Secara teknis, ini dimulai sebagai direktori kerja Anda tetapi dapat diubah menggunakan process.chdir().

Pengecualian adalah ketika Anda menggunakan .dengan require(). Jalur di dalam requireselalu relatif terhadap file yang berisi panggilan require.

Sebagai contoh...

Katakanlah struktur direktori Anda

/dir1
  /dir2
    pathtest.js

dan pathtest.jsberisi

var path = require("path");
console.log(". = %s", path.resolve("."));
console.log("__dirname = %s", path.resolve(__dirname));

dan kamu juga

cd /dir1/dir2
node pathtest.js

Anda mendapatkan

. = /dir1/dir2
__dirname = /dir1/dir2

Direktori kerja Anda adalah /dir1/dir2yang .memutuskan untuk itu. Karena pathtest.jsterletak di /dir1/dir2itulah yang __dirnamememutuskan untuk juga.

Namun, jika Anda menjalankan skrip dari /dir1

cd /dir1
node dir2/pathtest.js

Anda mendapatkan

. = /dir1
__dirname = /dir1/dir2

Dalam hal ini, direktori kerja Anda adalah /dir1yang harus .diselesaikan, tetapi__dirname masih memutuskan untuk melakukannya /dir1/dir2.

Menggunakan . di dalam require...

Jika di dalam dir2/pathtest.jsAnda memiliki requirepanggilan ke memasukkan file di dalam dir1Anda akan selalu melakukannya

require('../thefile')

karena path di dalamnya requireselalu relatif terhadap file yang Anda panggil itu. Ini tidak ada hubungannya dengan direktori kerja Anda.

d512
sumber
38
IMO, penjelasan ini sedikit lebih jelas daripada yang dari jawaban yang diterima (Anda tahu, "direktori saat ini" agak ambigu di sana).
Menjelma
5
Saya setuju. Saya akan mengubah jawaban yang diterima. Harap diingat bahwa jawaban ini ditambahkan 2,5 tahun setelah yang asli diterima, dan saya baru menyadarinya sekarang (2 tahun kemudian). :) Lebih baik terlambat daripada tidak sama sekali!
thisissami
14
Perlu dicatat bahwa ./tidak selalu direktori tempat simpul diluncurkan. Itu dimulai seperti itu, tetapi dapat diubah melalui process.chdir(). Jadi, ./selalu direktori kerja saat ini, yang biasanya merupakan simpul direktori yang diluncurkan, kecuali jika kode Anda secara eksplisit mengubah direktori kerja.
gilly3
3
Saya sedikit bingung tentang Penggunaan. inside membutuhkan bagian, jika path di dalam mengharuskan selalu relatif terhadap file yang Anda panggil, bukankah path harus memerlukan ('../ thefile') alih-alih memerlukan ('../ dir1 / thefile')? Saya pikir .. membawa posisi jalan saat ini kembali satu tingkat dari dir2 ke dir1. Apakah Anda masih perlu menempatkan dir1 di jalur atau apakah saya rindu memahami sesuatu?
andromada
1
Dan bagaimana yang akan Anda lakukan jika Anda perlu menggunakan ../someDirbeberapa skrip dan Anda akan menjalankan perintah dari folder yang berbeda?
cbdeveloper
154

./merujuk ke direktori kerja saat ini, kecuali dalam require()fungsi. Saat menggunakan require(), itu diterjemahkan ./ke direktori file saat ini disebut. __dirnameselalu merupakan direktori dari file saat ini.

Misalnya, dengan struktur file berikut

/home/user/dir/files/config.json

{
  "hello": "world"
}

/home/user/dir/files/somefile.txt

text file

/home/user/dir/dir.js

var fs = require('fs');

console.log(require('./files/config.json'));
console.log(fs.readFileSync('./files/somefile.txt', 'utf8'));

Jika saya cdmasuk /home/user/dirdan lari node dir.jssaya akan mendapatkan

{ hello: 'world' }
text file

Tetapi ketika saya menjalankan skrip yang sama dari /home/user/saya dapatkan

{ hello: 'world' }

Error: ENOENT, no such file or directory './files/somefile.txt'
    at Object.openSync (fs.js:228:18)
    at Object.readFileSync (fs.js:119:15)
    at Object.<anonymous> (/home/user/dir/dir.js:4:16)
    at Module._compile (module.js:432:26)
    at Object..js (module.js:450:10)
    at Module.load (module.js:351:31)
    at Function._load (module.js:310:12)
    at Array.0 (module.js:470:10)
    at EventEmitter._tickCallback (node.js:192:40)

Menggunakan ./bekerja dengan requiretetapi tidak untuk fs.readFileSync. Itu karena untuk fs.readFileSync, ./diterjemahkan ke dalam cwd (dalam hal ini /home/user/). Dan /home/user/files/somefile.txttidak ada.

fent
sumber
oh saya pikir __dirname adalah direktori kerja saat ini ... terima kasih atas klarifikasi!
thisissami
Apakah ada cara untuk merujuk direktori kerja aplikasi dengan fs? Misalnya, saya mencoba memuat file dari direktori yang berfungsi /movies, tetapi karena modul saya ada dalam file /custom_modules/, __dirnamecoba ambil filmnya dari,/custom_modules/movies
2
Anda bisa menggunakan ./atau process.cwd(). lihat nodejs.org/api/process.html#process_process_cwd
fent
Perlu dicatat itu bukan ide yang baik untuk menggunakan __dirname atas ./ dalam membutuhkan pernyataan karena meskipun mereka berperilaku identik dalam node, itu dapat menyebabkan masalah dengan peramban membangun untuk paket yang dengan mudah dinyatakan dihindari.
Jed Watson