В чем разница между __dirname и./в node.js?

При программировании в Node.js и ссылках на файлы, которые находятся где-то по отношению к вашему текущему каталогу, есть ли причина использовать переменную __dirname вместо обычного ./? Я использовал/до сих пор в своем коде и только что обнаружил существование __dirname и по сути хочу знать, будет ли разумным преобразовать мой./в это, и если да, то почему это было бы умным идея.

Ответ 1

Сущность

В Node.js, __dirname всегда находится каталог, в котором находится текущий исполняемый script (см. это). Поэтому, если вы набрали __dirname в /d1/d2/myscript.js, значение будет /d1/d2.

В отличие от этого, . дает вам каталог, из которого вы запустили команду node в окне терминала (т.е. в вашем рабочем каталоге).

Исключением является использование . с require(). Путь внутри require всегда относится к файлу, содержащему вызов require.

Например...

Скажем, ваша структура каталогов

/dir1
  /dir2
    pathtest.js

и pathtest.js содержит

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

и вы делаете

cd /dir1/dir2
node pathtest.js

вы получаете

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

Ваш рабочий каталог /dir1/dir2, чтобы разрешить .. Так как pathtest.js находится в /dir1/dir2, что также разрешает __dirname.

Однако, если вы запустите script из /dir1

cd /dir1
node dir2/pathtest.js

вы получаете

. = /dir1
__dirname = /dir1/dir2

В этом случае ваш рабочий каталог был /dir1, чтобы разрешить ., но __dirname по-прежнему разрешается /dir1/dir2.

Использование . внутри require...

Если внутри dir2/pathtest.js у вас есть вызов require для включения файла внутри dir1, вы бы всегда делаете

require('../thefile')

потому что путь внутри require всегда относится к файлу, в котором вы его вызываете. Это не имеет никакого отношения к вашему рабочему каталогу.

Ответ 2

./ относится к текущему рабочему каталогу, за исключением функции require(). При использовании require() он переводит ./ в каталог текущего файла. __dirname всегда является каталогом текущего файла.

Например, со следующей структурой файла

/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'));

Если я cd в /home/user/dir и запустите node dir.js, я получу

{ hello: 'world' }
text file

Но когда я запускаю тот же script из /home/user/, я получаю

{ 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)

Использование ./ работает с require, но не для fs.readFileSync. Это потому, что для fs.readFileSync, ./ переводится в cwd (в данном случае /home/user/). И /home/user/files/somefile.txt не существует.