Gibt es einen anderen Weg, außer process.cwd()
, um den Pfadnamen des Root-Verzeichnisses des aktuellen Projekts zu erhalten. Implementiert Node so etwas wie die Eigenschaft von Ruby, Rails.root
,. Ich bin auf der Suche nach etwas, das konstant und zuverlässig ist.
Antworten
Zu viele Anzeigen?Fügen Sie einfach diese Zeile zu Ihrem Modul im Root hinzu, normalerweise ist es app.js
o app.ts
.
global.__basedir = __dirname;
Dann wird _basedir für alle Ihre Module zugänglich sein.
Anmerkung: Für die Typescript-Implementierung folgen Sie dem obigen Schritt und können dann den Pfad zum Root-Verzeichnis verwenden, indem Sie global.__basedir
Versuchen Sie, sich von __dirname
bis Sie eine package.json
und entscheiden Sie, dass dies das Haupt-Root-Verzeichnis der Anwendung ist, zu dem Ihre aktuelle Datei gehört.
Según Knotenpunkt-Dokumente
Die package.json-Datei befindet sich normalerweise im Root-Verzeichnis eines Node.js-Projekts.
const fs = require('fs')
const path = require('path')
function getAppRootDir () {
let currentDir = __dirname
while(!fs.existsSync(path.join(currentDir, 'package.json'))) {
currentDir = path.join(currentDir, '..')
}
return currentDir
}
Ich habe festgestellt, dass dies bei mir immer funktioniert, auch wenn die Anwendung aus einem Unterordner aufgerufen wird, wie es bei einigen Test-Frameworks wie Mocha der Fall sein kann:
process.mainModule.paths[0].split('node_modules')[0].slice(0, -1);
Warum es funktioniert:
Zur Laufzeit erstellt node ein Register mit den vollständigen Pfaden aller geladenen Dateien. Die Module werden zuerst geladen und stehen daher an erster Stelle dieses Verzeichnisses. Durch Auswahl des ersten Elements des Verzeichnisses und Rückgabe des Pfads vor dem Verzeichnis "node_modules" können wir die Wurzel der Anwendung ermitteln.
Es ist nur eine Zeile Code, aber der Einfachheit halber (meinetwegen) habe ich ihn in ein NPM-Modul gepackt:
https://www.npmjs.com/package/node-Root.pddivine
Viel Spaß!
EDIT :
process.mainModule
es Abgelehnt ab Version 14.0.0
Utilice require.main
stattdessen:
require.main.paths[0].split('node_modules')[0].slice(0, -1);
Präambel
Dies ist eine sehr alte Frage, aber sie scheint im Jahr 2020 den Nerv der Zeit genauso zu treffen wie im Jahr 2012. Ich habe alle anderen Antworten durchgesehen und konnte die folgende Technik nicht finden (sie hat ihre eigenen Grenzen, aber auch die anderen sind nicht auf jede Situation anwendbar):
Git + untergeordneter Prozess
Wenn Sie Git als Ihre Versionskontrollsystem Das Problem der Bestimmung der Projektwurzel (die ich als die eigentliche Wurzel des Projekts ansehen würde - schließlich möchten Sie, dass Ihr VCS den größtmöglichen Sichtbarkeitsumfang hat) kann reduziert werden:
Repository abrufen Wurzelpfad
Da Sie dazu einen CLI-Befehl ausführen müssen, müssen wir einen Kindprozess erzeugen. Da es außerdem sehr unwahrscheinlich ist, dass sich das Projekt Root während der Laufzeit ändert, können wir die synchrone Version des Befehls child_process
Modul beim Start.
Ich fand spawnSync()
die für die Stelle am besten geeignet sind. Was den auszuführenden Befehl betrifft, git worktree
(mit einem --porcelain
zur Vereinfachung des Parsens) ist alles, was benötigt wird, um den absoluten Pfad der Wurzel abzurufen.
In dem Beispiel am Ende der Antwort habe ich mich dafür entschieden, ein Array von Pfaden zurückzugeben, weil es möglicherweise mehrere Arbeitsbäume (obwohl sie wahrscheinlich gemeinsame Wege haben), nur um sicher zu sein. Beachten Sie, dass wir einen CLI-Befehl verwenden, shell
sollte die Option true
(die Sicherheit sollte kein Problem darstellen, da es keine nicht vertrauenswürdige Eingabe gibt).
Vergleich von Ansätzen und Ausweichmöglichkeiten
Da ich weiß, dass eine Situation, in der VCS unzugänglich ist, möglich ist, habe ich nach der Analyse von Dokumenten und anderen Antworten ein paar Ausweichmöglichkeiten eingebaut. Die vorgeschlagenen Lösungen belaufen sich auf (ohne Module und Pakete von Drittanbietern):
Solución
Vorteil
Hauptproblem
zeigt auf die Moduldatei
relativ zum Modul
zeigt auf das Modulverzeichnis
gleich wie __filename
node_modules
Baumspaziergang
fast garantiert Wurzel
komplexe Baumwanderung bei Verschachtelung
path.resolve(".")
Wurzel, wenn CWD Wurzel ist
gleich wie process.cwd()
gleich wie __filename
gleich wie __filename
process.env.INIT_CWD
zeigt auf npm run
dir
erfordert npm
&& CLI-Start
process.env.PWD
zeigt auf das aktuelle Verzeichnis
relativ zu (ist das) Startverzeichnis
gleich wie env.PWD
process.chdir(path)
während der Laufzeit
Wurzel wenn === module
scheitert an require
d-Module
Aus der obigen Vergleichstabelle geht hervor, dass die folgenden Ansätze am universellsten sind:
require.main.filename
als eine einfache Möglichkeit, die Wurzel zu erhalten, wennrequire.main === module
erfüllt istnode_modules
Baumweg vorgeschlagen kürzlich geht von einer anderen Annahme aus:
wenn das Verzeichnis des Moduls den Namen
node_modules
dir im Inneren, ist es wahrscheinlich die Root
Für die Hauptanwendung wird der Anwendungsstamm und für ein Modul der Projektstamm verwendet.
Fallback 1. Baumlauf
Meine Implementierung verwendet einen laxeren Ansatz, indem sie anhält, sobald ein Zielverzeichnis gefunden wird, da für ein bestimmtes Modul dessen Root das Projekt-Root ist. Man kann die Aufrufe verketten oder sie erweitern, um die Suchtiefe konfigurierbar zu machen:
/**
* @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. Hauptmodul
Die zweite Implementierung ist trivial:
/**
* @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] :
[];
};
Umsetzung
Ich würde vorschlagen, den Tree Walker als bevorzugte Lösung zu verwenden, da er vielseitiger ist:
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);
};
Benachteiligungen
Die offensichtlichste ist, dass Git installiert und initialisiert werden muss, was unerwünscht/unplausibel sein kann (Nebenbemerkung: Git muss auf Produktionsservern installiert ist nicht ungewöhnlich, und es ist auch nicht unsicher ). Kann wie oben beschrieben durch Fallbacks vermittelt werden.