web-dev-qa-db-fra.com

Déterminer la racine du projet à partir d'une application node.js en cours d'exécution

Existe-t-il un meilleur moyen que process.cwd() pour déterminer le répertoire racine d'un processus node.js en cours d'exécution? Quelque chose comme l'équivalent de Rails.root, mais pour Node.js. Je cherche quelque chose qui soit aussi prévisible et fiable que possible.

250
MrEvil

Il y a plusieurs façons de procéder, chacune avec ses propres avantages et inconvénients:

require.main.filename

De http://nodejs.org/api/modules.html :

Lorsqu'un fichier est exécuté directement à partir d'un noeud, require.main est défini sur sa module. Cela signifie que vous pouvez déterminer si un fichier a été exécuté directement en testant require.main === module

Étant donné que module fournit une propriété filename (normalement équivalente à __filename), vous pouvez obtenir le point d’entrée de l’application actuelle en vérifiant require.main.filename.

Donc, si vous voulez le répertoire de base de votre application, vous pouvez faire:

var path = require('path');
var appDir = path.dirname(require.main.filename);

Avantages et inconvénients

Cela fonctionnera très bien la plupart du temps, mais si vous exécutez votre application avec un lanceur tel que pm2 ou que vous exécutez des tests mocha, cette méthode échouera.

global.X

Le noeud a un objet d'espace de nom global appelé global - tout ce que vous attachez à cet objet sera disponible partout dans votre application. Ainsi, dans votre index.js (ou app.js ou quel que soit le nom du fichier de votre application principale), vous pouvez simplement définir une variable globale:

// index.js
var path = require('path');
global.appRoot = path.resolve(__dirname);

// lib/moduleA/component1.js
require(appRoot + '/lib/moduleB/component2.js');

Avantages et inconvénients

Fonctionne de manière cohérente, mais vous devez compter sur une variable globale, ce qui signifie que vous ne pouvez pas réutiliser facilement les composants/etc.

process.cwd ()

Ceci retourne le répertoire de travail actuel. Pas fiable du tout, car tout dépend du répertoire dans lequel le processus a été lancé from:

$ cd /home/demo/
$ mkdir subdir
$ echo "console.log(process.cwd());" > subdir/demo.js
$ node subdir/demo.js
/home/demo
$ cd subdir
$ node demo.js
/home/demo/subdir

chemin-racine-app

Pour résoudre ce problème, j'ai créé un module de noeud appelé app-root-path . L'utilisation est simple:

var appRoot = require('app-root-path');
var myModule = require(appRoot + '/lib/my-module.js');

Le module app-root-path utilise plusieurs techniques différentes pour déterminer le chemin racine de l'application, en tenant compte des modules installés globalement (par exemple, si votre application s'exécute dans /var/www/ mais le module est installé dans ~/.nvm/v0.x.x/lib/node/). Cela ne fonctionnera pas 100% du temps, mais cela fonctionnera dans les scénarios les plus courants.

Avantages et inconvénients

Fonctionne sans configuration dans la plupart des cas. Fournit également quelques méthodes pratiques supplémentaires de Nice (voir la page du projet). Le plus gros problème est que ça ne marchera pas si:

  • Vous utilisez un lanceur, comme pm2
  • ET, le module n'est pas installé dans le répertoire node_modules de votre application (par exemple, si vous l'avez installé globalement)

Vous pouvez contourner ce problème en définissant une variable d'environnement APP_ROOT_PATH ou en appelant .setPath() sur le module, mais dans ce cas, vous feriez probablement mieux d'utiliser la méthode global.

Variable d'environnement NODE_PATH

Si vous cherchez un moyen de déterminer le chemin racine de l'application actuelle, l'une des solutions ci-dessus fonctionnera probablement mieux pour vous. Si, par contre, vous essayez de résoudre le problème du chargement fiable des modules de l'application, je vous recommande vivement de consulter la variable d'environnement NODE_PATH.

Le système Modules du nœud recherche des modules dans divers emplacements. L'un de ces emplacements est l'endroit où process.env.NODE_PATH points . Si vous définissez cette variable d'environnement, vous pouvez alors require modules avec le chargeur de modules standard sans autre modification.

Par exemple, si vous définissez NODE_PATH sur /var/www/lib, les opérations suivantes fonctionneront parfaitement:

require('module2/component.js');
// ^ looks for /var/www/lib/module2/component.js

Une excellente façon de faire consiste à utiliser npm:

"scripts": {
    "start": "NODE_PATH=. node app.js"
}

Maintenant, vous pouvez démarrer votre application avec npm start et vous êtes en or. Je combine cela avec mon module enforce-node-path , qui empêche le chargement accidentel de l'application sans NODE_PATH set. Pour encore plus de contrôle sur l'application des variables d'environnement, voir checkenv .

Un getcha:NODE_PATHdoit être défini en dehors de de l'application de nœud. Vous ne pouvez pas faire quelque chose comme process.env.NODE_PATH = path.resolve(__dirname) car le chargeur de modules met en cache la liste des répertoires qu'il recherchera avant que votre application ne soit exécutée.

[ajouté le 06/06/16] Un autre module vraiment prometteur qui tente de résoudre ce problème est ondulé .

493
inxilpro

__dirname n'est pas un global; il est local par rapport au module actuel, de sorte que chaque fichier a sa propre valeur locale différente.

Si vous voulez le répertoire racine du processus en cours, vous souhaiterez probablement utiliser process.cwd().

Si vous voulez de la prévisibilité et de la fiabilité, vous devrez probablement obliger votre application à définir une certaine variable d'environnement. Votre application cherche MY_APP_HOME (Ou peu importe) et si elle existe, et que l'application existe dans ce répertoire, tout va bien. S'il n'est pas défini ou si le répertoire ne contient pas votre application, une erreur devrait se fermer et inviter l'utilisateur à créer la variable. Il pourrait être défini dans le cadre d'un processus d'installation.

Vous pouvez lire les variables d'environnement dans le noeud avec quelque chose comme process.env.MY_ENV_VARIABLE.

47
izb

1- créer un fichier à la racine du projet, appelez-le settings.js

2- Dans ce fichier, ajoutez ce code

module.exports = {
    POST_MAX_SIZE : 40 , //MB
    UPLOAD_MAX_FILE_SIZE: 40, //MB
    PROJECT_DIR : __dirname
};

3- Dans node_modules, créez un nouveau module et nommez-le "settings". Dans le module index.js, écrivez ce code:

module.exports = require("../../settings");

4- et quand vous voulez que votre répertoire de projet utilise simplement 

var settings = require("settings");
settings.PROJECT_DIR; 

de cette façon, vous aurez tous les répertoires de projet relatifs à ce fichier;)

42
Fareed Alnamrouti

le moyen le plus simple d'obtenir la racine globale ( en supposant que vous utilisez NPM pour exécuter votre application node.js 'npm start', etc. )

var appRoot = process.env.PWD;

Si vous souhaitez effectuer une vérification croisée de ce qui précède

Supposons que vous souhaitiez recouper process.env.PWD avec les paramètres de votre application node.js. si vous voulez que certains tests d'exécution vérifient la validité de process.env.PWD, vous pouvez le vérifier avec ce code (celui que j'ai écrit et qui semble bien fonctionner). Vous pouvez vérifier le nom du dernier dossier dans appRoot avec le nom_package_npm dans votre fichier package.json, par exemple:

    var path = require('path');

    var globalRoot = __dirname; //(you may have to do some substring processing if the first script you run is not in the project root, since __dirname refers to the directory that the file is in for which __dirname is called in.)

    //compare the last directory in the globalRoot path to the name of the project in your package.json file
    var folders = globalRoot.split(path.sep);
    var packageName = folders[folders.length-1];
    var pwd = process.env.PWD;
    var npmPackageName = process.env.npm_package_name;
    if(packageName !== npmPackageName){
        throw new Error('Failed check for runtime string equality between globalRoot-bottommost directory and npm_package_name.');
    }
    if(globalRoot !== pwd){
        throw new Error('Failed check for runtime string equality between globalRoot and process.env.PWD.');
    }

vous pouvez également utiliser ce module NPM: require('app-root-path') qui fonctionne très bien à cet effet

17
Alexander Mills

J'ai constaté que cela fonctionnait de manière cohérente pour moi, même lorsque l'application est appelée à partir d'un sous-dossier, comme cela peut être le cas avec certains frameworks de test, tels que 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 renvoyant le chemin avant le répertoire 'node_modules', nous pouvons déterminer la racine de l'application.

Ce n'est qu'une ligne de code, mais par souci de simplicité, je l'ai mis dans une boîte noire dans un module NPM:

https://www.npmjs.com/package/node-root.pddivine

Prendre plaisir!

10
Patrick

Peut-être que vous pouvez essayer de parcourir le code __filename vers le haut jusqu'à ce que vous trouviez un package.json, puis décidez que c'est le répertoire principal de votre fichier actuel.

6
kvz

Tous ces "répertoires racine" ont généralement besoin de résoudre un chemin virtuel en un chemin de pile, alors vous devriez peut-être regarder path.resolve?

var path= require('path');
var filePath = path.resolve('our/virtual/path.ext");
6
Konstantin Isaev

En fait, je trouve la solution peut-être la plus simple: la plus robuste:

import * as path from 'path'
const projectRootPath = path.resolve(__dirname)
export const rootPath = projectRootPath
4
Avi Tshuva

Une technique que j'ai trouvée utile lors de l'utilisation de l'express consiste à ajouter ce qui suit à app.js avant de définir l'un de vos autres itinéraires

// set rootPath
app.use(function(req, res, next) {
  req.rootPath = __dirname;
  next();
});

app.use('/myroute', myRoute);

Pas besoin d'utiliser globals et vous avez le chemin du répertoire racine en tant que propriété de l'objet de la demande.

Cela fonctionne si votre app.js se trouve à la racine de votre projet, c'est-à-dire par défaut.

2
Ben Davies

Je sais que celui-ci est déjà trop tard. Mais nous pouvons récupérer l'URL racine par deux méthodes

1ère méthode

var path = require('path');
path.dirname(require.main.filename);

2ème méthode

var path = require('path');
path.dirname(process.mainModule.filename);

Lien de référence: - https://Gist.github.com/geekiam/e2e3e0325abd9023d3a3

1
VIKAS KOHLI

Aussi simple que d'ajouter cette ligne à votre module en racine, il s'agit généralement de app.js

global.__basedir = __dirname;

Ensuite, _basedir sera accessible à tous vos modules.

0
didxga
process.mainModule.paths
  .filter(p => !p.includes('node_modules'))
  .shift()

Obtenez tous les chemins dans les modules principaux et filtrez ceux avec "node_modules", Puis obtenez le premier de la liste de chemins restante Un comportement inattendu ne provoquera pas d'erreur, mais une undefined.

Fonctionne bien pour moi, même lorsque vous appelez ie $ mocha.

0
Andre Figueiredo

Trouver le chemin racine d'une application électronique pourrait être délicat. Parce que le chemin racine est différent pour le processus principal et le moteur de rendu dans différentes conditions telles que la production, le développement et les conditions empaquetées.

J'ai écrit un paquet npm electron-root-path pour capturer le chemin racine d'une application électronique.

$ npm install electron-root-path

or 

$ yarn add electron-root-path


// Import ES6 way
import { rootPath } from 'electron-root-path';

// Import ES2015 way
const rootPath = require('electron-root-path').rootPath;

// e.g:
// read a file in the root
const location = path.join(rootPath, 'package.json');
const pkgInfo = fs.readFileSync(location, { encoding: 'utf8' });
0
Ganesh Rathinavel

En haut du fichier principal, ajoutez:

mainDir = __dirname;

Puis utilisez-le dans n'importe quel fichier dont vous avez besoin:

console.log('mainDir ' + mainDir);
  • mainDir est défini globalement, si vous en avez besoin uniquement dans le fichier actuel - utilisez plutôt __dirname.
  • le fichier principal se trouve généralement dans le dossier racine du projet et porte les noms main.js, index.js, gulpfile.js.
0
Dariusz Sikorski

__dirname vous donnera le répertoire racine, tant que vous êtes dans un fichier qui se trouve dans le répertoire racine.

0
Andrew Koster

Vous pouvez simplement ajouter le chemin du répertoire racine dans la variable de l'application express et obtenir ce chemin à partir de l'application. Pour cela, ajoutez app.set('rootDirectory', __dirname); dans votre fichier index.js ou app.js. Et utilisez req.app.get('rootDirectory') pour obtenir le chemin du répertoire racine dans votre code.

0
Pulkit Aggarwal

Faites-le sexy ????????.

const users = require('../../../database/users'); // ???? what you have
// OR
const users = require('$db/users'); // ???? no matter how deep you are
const products = require('/database/products'); // ???? alias or pathing from root directory


Trois étapes simples pour résoudre le problème du sentier moche.

  1. Installez le paquet: npm install sexy-require --save
  2. Incluez require('sexy-require') une fois en haut de votre fichier d’application principal.

    require('sexy-require');
    const routers = require('/routers');
    const api = require('$api');
    ...
    
  3. Étape facultative. La configuration du chemin peut être définie dans le fichier .paths du répertoire racine de votre projet.

    $db = /server/database
    $api-v1 = /server/api/legacy
    $api-v2 = /server/api/v2
    
0
sultan

Ajoutez-le quelque part au début de votre fichier d’application principal (par exemple, app.js):

global.__basedir = __dirname;

Ceci définit une variable globale qui sera toujours équivalente au répertoire de base de votre application. Utilisez-le comme n'importe quelle autre variable:

const yourModule = require(__basedir + '/path/to/module.js');

Simple...

0
Pankaj Shinde

Vieille question, je sais, cependant aucune question de mentionner à utiliser progress.argv. Le tableau argv inclut un chemin complet et un nom de fichier (avec ou sans extension .js) utilisé comme paramètre à exécuter par noeud. Parce que cela peut aussi contenir des drapeaux, vous devez filtrer cela.

Ce n’est pas un exemple que vous pouvez utiliser directement (à cause de l’utilisation de mon propre framework) mais je pense que cela vous donne une idée de la façon de le faire. J'utilise également une méthode de cache pour éviter que l'appel de cette fonction ne sollicite trop le système, surtout lorsqu'aucune extension n'est spécifiée (et qu'une vérification de l'existence d'un fichier est requise), par exemple:

node myfile

ou

node myfile.js

C'est la raison pour laquelle je le cache, voir aussi le code ci-dessous.


function getRootFilePath()
{
        if( !isDefined( oData.SU_ROOT_FILE_PATH ) )
        {
            var sExt = false;

            each( process.argv, function( i, v )
            {
                 // Skip invalid and provided command line options
                if( !!v && isValidString( v ) && v[0] !== '-' )
                {
                    sExt = getFileExt( v );

                    if( ( sExt === 'js' ) || ( sExt === '' && fileExists( v+'.js' )) )
                    {

                        var a = uniformPath( v ).split("/"); 

                         // Chop off last string, filename
                        a[a.length-1]='';

                         // Cache it so we don't have to do it again.
                        oData.SU_ROOT_FILE_PATH=a.join("/"); 

                         // Found, skip loop
                        return true;
                    }
                }
            }, true ); // <-- true is: each in reverse order
        }

        return oData.SU_ROOT_FILE_PATH || '';
    }
}; 
0
Codebeat

Crée une fonction dans app.js

/*Function to get the app root folder*/

var appRootFolder = function(dir,level){
    var arr = dir.split('\\');
    arr.splice(arr.length - level,level);
    var rootFolder = arr.join('\\');
    return rootFolder;
}

// view engine setup
app.set('views', path.join(appRootFolder(__dirname,1),'views'));
0
Karthik M