Y a-t-il un autre moyen, autre que process.cwd()
pour obtenir le nom du chemin du répertoire racine du projet en cours. Est-ce que Node implémente quelque chose comme la propriété de Ruby, Rails.root
,. Je cherche quelque chose qui soit constant et fiable.
Réponses
Trop de publicités?Il suffit d'ajouter cette ligne à votre module dans la racine, généralement c'est app.js
ou app.ts
.
global.__basedir = __dirname;
Alors _basedir sera accessible à tous vos modules.
Note : Pour l'implémentation de typescript, suivez l'étape ci-dessus et vous serez alors en mesure d'utiliser le chemin du répertoire racine en utilisant global.__basedir
J'ai constaté que cela fonctionne systématiquement pour moi, même lorsque l'application est invoquée à partir d'un sous-dossier, comme cela peut être le cas avec certains cadres de test, comme Mocha :
process.mainModule.paths[0].split('node_modules')[0].slice(0, -1);
Pourquoi ça marche :
Au moment de l'exécution, le nœud crée un registre des chemins complets de tous les fichiers chargés. Les modules sont chargés en premier, et donc en haut de ce registre. En sélectionnant le premier élément du registre et en retournant le chemin avant le répertoire 'node_modules', nous sommes en mesure de déterminer la racine de l'application.
Il ne s'agit que d'une ligne de code, mais pour des raisons de simplicité (et pour moi), je l'ai intégrée dans un module NPM :
https://www.npmjs.com/package/node-Root.pddivine
Profitez-en !
Préambule
Cette question est très ancienne, mais elle semble toucher la corde sensible en 2020 autant qu'en 2012. J'ai vérifié toutes les autres réponses et je n'ai pas trouvé la technique suivante mentionnée (elle a ses propres limites, mais les autres ne sont pas non plus applicables à toutes les situations) :
Git + processus enfant
Si vous utilisez Git comme système de contrôle des versions Dans ce cas, le problème de la détermination de la racine du projet peut être réduit à (ce que je considérerais comme la racine correcte du projet - après tout, vous voudriez que votre VCS ait la plus grande visibilité possible) :
récupérer le référentiel Chemin racine
Puisque vous devez exécuter une commande CLI pour le faire, nous devons créer un processus enfant. De plus, comme il est très peu probable que le projet Root change en cours d'exécution, nous pouvons utiliser la version synchrone de la commande child_process
au démarrage.
J'ai trouvé spawnSync()
pour être le plus approprié pour le travail. Quant à la commande à exécuter, git worktree
(avec un --porcelain
pour faciliter l'analyse syntaxique) est tout ce qui est nécessaire pour récupérer le chemin absolu de la racine.
Dans l'exemple à la fin de la réponse, j'ai choisi de retourner un tableau de chemins parce qu'il pourrait y avoir arbres de travail multiples (bien qu'ils soient susceptibles d'avoir des chemins communs) juste pour être sûr. Notez que lorsque nous utilisons une commande CLI, shell
doit être définie comme suit true
(la sécurité ne devrait pas être un problème puisqu'il n'y a pas d'entrée non fiable).
Comparaison des approches et solutions de repli
Comprenant qu'une situation où VCS peut être inaccessible est possible, j'ai inclus quelques solutions de repli après avoir analysé la documentation et d'autres réponses. Les solutions proposées se résument à (à l'exclusion des modules et paquets tiers) :
Solution
Avantage
Problème principal
pointe vers le fichier du module
par rapport au module
pointe vers le répertoire du module
même que __filename
node_modules
promenade en forêt
Racine presque garantie
marche arborescente complexe si imbriquée
path.resolve(".")
Racine si le CWD est racine
même que process.cwd()
même que __filename
même que __filename
process.env.INIT_CWD
Les points suivants npm run
dir
nécessite npm
&& Lancement de CLI
process.env.PWD
pointe vers le répertoire actuel
relatif à (est le) répertoire de lancement
même que env.PWD
process.chdir(path)
au moment de l'exécution
Racine si === module
échoue sur require
d modules
D'après le tableau comparatif ci-dessus, les approches suivantes sont les plus universelles :
-
require.main.filename
comme un moyen facile d'obtenir la Racine sirequire.main === module
est respecté -
node_modules
promenade dans les arbres proposée récemment utilise une autre hypothèse :
si le répertoire du module a
node_modules
dir à l'intérieur, il est probable que ce soit la racine
Pour l'application principale, il obtiendra la racine de l'application et pour un module - la racine de son projet.
Fallback 1. Marche dans l'arbre
Mon implémentation utilise une approche plus laxiste en s'arrêtant dès qu'un répertoire cible est trouvé car pour un module donné, sa racine est la racine du projet. On peut enchaîner les appels ou les étendre pour rendre la profondeur de recherche configurable :
/**
* @summary gets root by walking up node_modules
* @param {import("fs")} fs
* @param {import("path")} pt
*/
const getRootFromNodeModules = (fs, pt) =>
/**
* @param {string} [startPath]
* @returns {string[]}
*/
(startPath = __dirname) => {
//avoid loop if reached root path
if (startPath === pt.parse(startPath).root) {
return [startPath];
}
const isRoot = fs.existsSync(pt.join(startPath, "node_modules"));
if (isRoot) {
return [startPath];
}
return getRootFromNodeModules(fs, pt)(pt.dirname(startPath));
};
Fallback 2. Module principal
La deuxième mise en œuvre est triviale :
/**
* @summary gets app entry point if run directly
* @param {import("path")} pt
*/
const getAppEntryPoint = (pt) =>
/**
* @returns {string[]}
*/
() => {
const { main } = require;
const { filename } = main;
return main === module ?
[pt.parse(filename).dir] :
[];
};
Mise en œuvre
Je suggère d'utiliser le marcheur d'arbre comme solution de rechange préférée car il est plus polyvalent :
const { spawnSync } = require("child_process");
const pt = require('path');
const fs = require("fs");
/**
* @summary returns worktree root path(s)
* @param {function : string[] } [fallback]
* @returns {string[]}
*/
const getProjectRoot = (fallback) => {
const { error, stdout } = spawnSync(
`git worktree list --porcelain`,
{
encoding: "utf8",
shell: true
}
);
if (!stdout) {
console.warn(`Could not use GIT to find root:\n\n${error}`);
return fallback ? fallback() : [];
}
return stdout
.split("\n")
.map(line => {
const [key, value] = line.split(/\s+/) || [];
return key === "worktree" ? value : "";
})
.filter(Boolean);
};
Inconvénients
Le plus évident est d'avoir Git installé et initialisé, ce qui peut être indésirable/implausible (remarque : avoir Git installé sur les serveurs de production n'est pas rare, pas plus qu'il n'est non sécurisé ). Peut être médiatisé par des solutions de repli comme décrit ci-dessus.