Qual é a diferença entre __dirname e ./ no node.js?

498

Ao programar no Node.js e referenciar arquivos localizados em algum lugar em relação ao seu diretório atual, existe algum motivo para usar a __dirnamevariável em vez de apenas uma regular ./? Eu tenho usado ./ até agora no meu código e descobri a existência de __dirname, e quero essencialmente saber se seria inteligente converter meus ./ para isso e, se sim, por que essa seria uma idéia inteligente .

thisissami
fonte
47
tl; dr: Então, basicamente, a diferença é que './' e 'process.cwd ()' se referem ao diretório atual do terminal que chama o script, enquanto o '__dirname' refere-se ao diretório em que o script é armazenado.
Gui Imamura
1
Exceto quando .é usado dentro require. O caminho interno requireé sempre relativo ao arquivo que contém a chamada para require.
Govind Rai

Respostas:

814

A essência

No Node.js, __dirnameé sempre o diretório em que o script atualmente em execução reside ( veja isso ). Então, se você digitou __dirnameem /d1/d2/myscript.js, o valor seria /d1/d2.

Por outro lado, .fornece o diretório a partir do qual você executou o nodecomando na janela do terminal (ou seja, o diretório de trabalho) quando você usa bibliotecas como pathe fs. Tecnicamente, ele começa como seu diretório de trabalho, mas pode ser alterado usando process.chdir().

A exceção é quando você usa .com require(). O caminho interno requireé sempre relativo ao arquivo que contém a chamada para require.

Por exemplo...

Digamos que sua estrutura de diretórios seja

/dir1
  /dir2
    pathtest.js

e pathtest.jscontém

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

e você faz

cd /dir1/dir2
node pathtest.js

você recebe

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

Seu diretório de trabalho é /dir1/dir2o que .resolve. Desde que pathtest.jsestá localizado em /dir1/dir2que é o que __dirnameresolve também.

No entanto, se você executar o script a partir de /dir1

cd /dir1
node dir2/pathtest.js

você recebe

. = /dir1
__dirname = /dir1/dir2

Nesse caso, seu diretório de trabalho era /dir1e foi assim que .resolveu, mas __dirnameainda resolve /dir1/dir2.

Usando .dentro require...

Se dentro de dir2/pathtest.jsvocê tiver uma requirechamada para incluir um arquivo dentro, dir1você sempre faria

require('../thefile')

porque o caminho interno requireé sempre relativo ao arquivo no qual você está chamando. Não tem nada a ver com o seu diretório de trabalho.

d512
fonte
38
Na IMO, essa explicação é um pouco mais clara que a da resposta aceita (você sabe, "o diretório atual" é um pouco ambíguo).
encarnou
5
Concordo. Vou mudar a resposta aceita. Lembre-se de que esta resposta foi adicionada 2,5 anos após a original ter sido aceita, e eu só a notei agora (outros 2 anos depois). :) Antes tarde do que nunca!
precisa saber é o seguinte
14
Vale ressaltar que ./nem sempre é o diretório em que o nó foi iniciado. Começa assim, mas pode ser alterado via process.chdir(). Portanto, ./sempre é o diretório de trabalho atual, que geralmente é o nó do diretório, a menos que seu código altere explicitamente o diretório de trabalho.
precisa saber é o seguinte
3
Estou um pouco confuso sobre o uso. inside exigir parte, se o caminho dentro de exigir é sempre relativo ao arquivo que você está chamando, o caminho não deve ser obrigatório ('../arquivo') em vez de exigir ('../dir1 / arquivo')? Eu pensei que o .. trazer a posição atual do caminho de volta um nível de dir2 para dir1 já. Você ainda precisa colocar dir1 no caminho ou sinto falta de algo?
precisa saber é o seguinte
1
E como você faria se precisasse usar ../someDiralgum script e executar o comando em uma pasta diferente?
Cbdeveloper 5/11/19
154

./refere-se ao diretório de trabalho atual, exceto na require()função Ao usá- require()lo, ele se traduz ./no diretório do arquivo atual chamado. __dirnameé sempre o diretório do arquivo atual.

Por exemplo, com a seguinte estrutura de arquivo

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

Se eu cdentrar /home/user/dire correr node dir.js, terei

{ hello: 'world' }
text file

Mas quando executo o mesmo script /home/user/, recebo

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

Usando ./trabalhou com requiremas não para fs.readFileSync. Isso porque fs.readFileSync, ./traduz-se no cwd (neste caso /home/user/). E /home/user/files/somefile.txtnão existe.

fent
fonte
oh, pensei que __dirname fosse o diretório de trabalho atual ... obrigado pelo esclarecimento!
thisissami
Existe alguma maneira de referenciar o diretório de trabalho do aplicativo com fs? Por exemplo, eu estou tentando carregar um arquivo do diretório de trabalho /movies, mas desde que meu módulo está em um arquivo /custom_modules/, __dirnametenta agarrar o filme a partir,/custom_modules/movies
2
Você pode usar ./ou process.cwd(). veja nodejs.org/api/process.html#process_process_cwd
fent
Vale ressaltar que não é uma boa idéia usar __dirname sobre ./ em instruções exigem, porque, embora se comportem de forma idêntica no nó, isso pode causar problemas nas compilações do browserify para pacotes que são facilmente evitados.
Jed Watson