Quelle est la différence entre __dirname et ./ dans node.js?

498

Lors de la programmation dans Node.js et du référencement de fichiers situés quelque part par rapport à votre répertoire actuel, y a-t-il une raison d'utiliser la __dirnamevariable au lieu d'un simple habituel ./? J'ai utilisé ./ jusqu'à présent dans mon code et je viens de découvrir l'existence de __dirname, et je veux essentiellement savoir s'il serait intelligent de convertir mes ./ en cela, et si oui, pourquoi ce serait une idée intelligente .

thisissami
la source
47
tl; dr: Donc, fondamentalement, la différence est que './' et 'process.cwd ()' font référence au répertoire courant du terminal appelant le script, tandis que le '__dirname' fait référence au répertoire dans lequel le script est stockée.
Gui Imamura
1
Sauf quand .est utilisé à l'intérieur require. Le chemin à l'intérieur requireest toujours relatif au fichier contenant l'appel à require.
Govind Rai

Réponses:

814

L'essentiel

Dans Node.js, se __dirnametrouve toujours le répertoire dans lequel réside le script en cours d'exécution ( voir ceci ). Donc , si vous avez tapé __dirnamedans /d1/d2/myscript.js, la valeur serait /d1/d2.

En revanche, .vous donne le répertoire à partir duquel vous avez exécuté la nodecommande dans votre fenêtre de terminal (c'est-à-dire votre répertoire de travail) lorsque vous utilisez des bibliothèques comme pathet fs. Techniquement, il commence comme votre répertoire de travail mais peut être modifié à l'aide de process.chdir().

L'exception est lorsque vous utilisez .avec require(). Le chemin à l'intérieur requireest toujours relatif au fichier contenant l'appel à require.

Par exemple...

Disons que la structure de votre répertoire est

/dir1
  /dir2
    pathtest.js

et pathtest.jscontient

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

et vous faites

cd /dir1/dir2
node pathtest.js

vous obtenez

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

Votre répertoire de travail est /dir1/dir2ainsi .résolu. Puisque pathtest.jsse trouve dans /dir1/dir2c'est ce qui se __dirnamerésout également.

Cependant, si vous exécutez le script à partir de /dir1

cd /dir1
node dir2/pathtest.js

vous obtenez

. = /dir1
__dirname = /dir1/dir2

Dans ce cas, votre répertoire de travail était /dir1donc c'est ce qui a été .résolu, mais __dirnamese résout toujours à /dir1/dir2.

Utilisation à l' .intérieur require...

Si l' intérieur dir2/pathtest.jsvous avez un requireappel en inclure un fichier à l' intérieur dir1vous toujours faire

require('../thefile')

car le chemin à l'intérieur requireest toujours relatif au fichier dans lequel vous l'appelez. Cela n'a rien à voir avec votre répertoire de travail.

d512
la source
38
OMI, cette explication est un peu plus claire que celle de la réponse acceptée (vous savez, "le répertoire courant" est un peu ambigu là-bas).
incarné
5
Je suis d'accord. Je vais changer la réponse acceptée. Veuillez garder à l'esprit que cette réponse a été ajoutée 2,5 ans après l'acceptation de la réponse originale, et je viens juste de la remarquer (2 ans plus tard). :) Mieux vaut tard que jamais!
thisissami
14
Il convient de noter que ce ./n'est pas toujours le répertoire à partir duquel le nœud a été lancé. Cela commence de cette façon, mais peut être modifié via process.chdir(). Il ./s'agit donc toujours du répertoire de travail actuel, qui est généralement le nœud de répertoire à partir duquel le nœud a été lancé, sauf si votre code a explicitement modifié le répertoire de travail.
gilly3
3
Je suis un peu confus au sujet de l'utilisation. à l'intérieur de la partie require, si le chemin à l'intérieur de require est toujours relatif au fichier que vous appelez, le chemin ne devrait-il pas être require ('../ thefile') au lieu de require ('../ dir1 / thefile')? je pensais que le .. ramène déjà la position actuelle du chemin d'un niveau de dir2 à dir1. Avez-vous encore besoin de mettre dir1 sur le chemin ou est-ce que je ne comprends pas quelque chose?
andromada
1
Et comment feriez-vous si vous devez utiliser ../someDirdans un script et que vous allez exécuter la commande à partir d'un dossier différent?
cbdeveloper
154

./fait référence au répertoire de travail courant, sauf dans la require()fonction. Lors de l'utilisation require(), il se traduit ./dans le répertoire du fichier actuel appelé. __dirnameest toujours le répertoire du fichier courant.

Par exemple, avec la structure de fichiers suivante

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

Si cdj'entre /home/user/diret que node dir.jsje cours, j'aurai

{ hello: 'world' }
text file

Mais quand je lance le même script que /home/user/je reçois

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

L'utilisation a ./fonctionné avec requiremais pas pour fs.readFileSync. C'est parce que fs.readFileSync, se ./traduit par le cwd (dans ce cas /home/user/). Et /home/user/files/somefile.txtn'existe pas.

fent
la source
oh je pensais que __dirname était le répertoire de travail actuel ... merci pour la clarification!
thisissami
Existe-t-il un moyen de référencer le répertoire de travail de l'application avec fs? Par exemple, j'essaie de charger un fichier à partir du répertoire de travail /movies, mais comme mon module se trouve dans un fichier /custom_modules/, il __dirnameessaie de récupérer le film depuis,/custom_modules/movies
2
Vous pouvez utiliser ./ou process.cwd(). voir nodejs.org/api/process.html#process_process_cwd
fent
Il convient de noter que ce n'est pas une bonne idée d'utiliser __dirname sur ./ dans les instructions require car bien qu'elles se comportent de manière identique dans le noeud, cela peut entraîner des problèmes avec les builds browserify pour les packages qui sont facilement évités autrement.
Jed Watson