Determina la root del progetto da un’applicazione node.js in esecuzione

C’è un modo migliore di process.cwd() per determinare la directory root di un processo node.js in esecuzione? Qualcosa come l’equivalente di Rails.root , ma per Node.js. Sto cercando qualcosa che sia il più prevedibile e affidabile ansible.

Ci sono diversi modi per affrontare questo, ognuno con i propri pro e contro:

require.main.filename

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

Quando un file viene eseguito direttamente dal nodo, require.main è impostato sul suo module . Ciò significa che è ansible determinare se un file è stato eseguito direttamente testando require.main === module

Poiché il module fornisce una proprietà filename (normalmente equivalente a __filename ), è ansible ottenere il punto di ingresso dell’applicazione corrente controllando require.main.filename .

Quindi se vuoi la directory di base per la tua app, puoi fare:

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

Pro e contro

Questo funzionerà molto spesso , ma se stai eseguendo la tua app con un launcher come pm2 o eseguendo test di moka , questo metodo fallirà.

global.X

Il nodo ha un object spazio dei nomi globale chiamato global : tutto ciò che viene allegato a questo object sarà disponibile ovunque nella tua app. Quindi, nel tuo index.js (o app.js o qualunque sia il nome del tuo file principale dell’app), puoi semplicemente definire una variabile globale:

 // index.js var path = require('path'); global.appRoot = path.resolve(__dirname); // lib/moduleA/component1.js require(appRoot + '/lib/moduleB/component2.js'); 

Pro e contro

Funziona in modo coerente ma devi fare affidamento su una variabile globale, il che significa che non puoi facilmente riutilizzare i componenti / ecc.

process.cwd ()

Questo restituisce la directory di lavoro corrente. Non affidabile, poiché dipende interamente dalla directory da cui è stato avviato il processo:

 $ 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 

app-root-path

Per risolvere questo problema, ho creato un modulo nodo chiamato app-root-path . L’utilizzo è semplice:

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

Il modulo app-root-path utilizza diverse tecniche per determinare il percorso root dell’app, tenendo conto di moduli installati globalmente (ad esempio, se l’app è in esecuzione in /var/www/ ma il modulo è installato in ~/.nvm/v0.xx/lib/node/ ). Non funzionerà il 100% delle volte, ma funzionerà negli scenari più comuni.

Pro e contro

Funziona senza configurazione nella maggior parte dei casi. Fornisce anche alcuni buoni metodi di convenienza aggiuntivi (vedi la pagina del progetto). La più grande truffa è che non funzionerà se:

  • Stai usando un launcher, come pm2
  • E , il modulo non è installato all’interno della directory node_modules dell’app (ad esempio, se è stato installato a livello globale)

Puoi aggirare questo problema impostando una variabile ambientale APP_ROOT_PATH o chiamando .setPath() sul modulo, ma in questo caso, probabilmente stai meglio usando il metodo global .

Variabile ambientale NODE_PATH

Se stai cercando un modo per determinare il percorso root dell’app corrente, è probabile che una delle soluzioni precedenti funzioni meglio per te. Se, d’altra parte, stai cercando di risolvere il problema del caricamento affidabile dei moduli di app, ti consiglio vivamente di esaminare la variabile ambientale NODE_PATH .

Il sistema Node’s Modules cerca i moduli in una varietà di posizioni. Una di queste posizioni è ovunque punti process.env.NODE_PATH . Se si imposta questa variabile ambientale, è ansible require moduli con il caricatore di moduli standard senza altre modifiche.

Ad esempio, se si imposta NODE_PATH su /var/www/lib , il seguente potrebbe funzionare NODE_PATH :

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

Un ottimo modo per farlo è usare npm :

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

Ora puoi avviare la tua app con npm start e sei d’oro. Lo combino con il mio modulo enforce-node-path , che impedisce di caricare accidentalmente l’app senza il set NODE_PATH . Per un controllo ancora maggiore sull’applicazione delle variabili ambientali, vedere checkenv .

Un NODE_PATH : NODE_PATH deve essere impostato all’esterno dell’app nodo. Non puoi fare qualcosa come process.env.NODE_PATH = path.resolve(__dirname) perché il loader del modulo memorizza nella cache l’elenco delle directory che cercherà prima dell’esecuzione dell’app.

[aggiunto il 4/6/16] Un altro modulo davvero promettente che tenta di risolvere questo problema è ondulato .

__dirname non è globale; è locale rispetto al modulo corrente, quindi ogni file ha il proprio valore locale diverso.

Se si desidera la directory root del processo in esecuzione, probabilmente si vorrà utilizzare process.cwd() .

Se si desidera la prevedibilità e l’affidabilità, probabilmente è necessario renderlo un requisito della propria applicazione in base al quale viene impostata una determinata variabile di ambiente. La tua app cerca MY_APP_HOME (o qualsiasi altra cosa) e se è lì, e l’applicazione esiste in quella directory, tutto va bene. Se non è definito o la directory non contiene l’applicazione, dovrebbe uscire con un errore che richiede all’utente di creare la variabile. Potrebbe essere impostato come parte di un processo di installazione.

È ansible leggere le variabili di ambiente nel nodo con qualcosa come process.env.MY_ENV_VARIABLE .

1- creare un file nella root del progetto chiamarlo settings.js

2- all’interno di questo file aggiungere questo codice

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

3- dentro node_modules crea un nuovo modulo name “settings” e all’interno del module index.js scrivi questo codice:

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

4- e ogni volta che si desidera utilizzare la directory del progetto

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

in questo modo avrai tutte le directory di progetto relative a questo file;)

il modo più semplice per ottenere la radice globale ( supponendo che tu usi NPM per eseguire l’app node.js ‘npm start’, ecc. )

 var appRoot = process.env.PWD; 

Se si desidera verificare in modo incrociato quanto sopra

Supponiamo che tu voglia eseguire il controllo incrociato di process.env.PWD con le impostazioni della tua applicazione node.js. se vuoi test di runtime per verificare la validità di process.env.PWD , puoi effettuare un controllo incrociato con questo codice (che ho scritto che sembra funzionare bene). È ansible eseguire il controllo incrociato del nome dell’ultima cartella in appRoot con npm_package_name nel file package.json, ad esempio:

  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.'); } 

puoi anche usare questo modulo NPM: require('app-root-path') che funziona molto bene per questo scopo

Ho trovato questo funziona in modo coerente per me, anche quando l’applicazione viene richiamata da una sottocartella, come può essere con alcuni framework di test, come Mocha:

 process.mainModule.paths[0].split('node_modules')[0].slice(0, -1); 

Perché funziona:

Al nodo di runtime crea un registro dei percorsi completi di tutti i file caricati. I moduli vengono caricati prima e quindi nella parte superiore di questo registro. Selezionando il primo elemento del registro e restituendo il percorso prima della directory ‘node_modules’, siamo in grado di determinare la radice dell’applicazione.

È solo una riga di codice, ma per motivi di semplicità (il mio bene), l’ho inserito in nero in un modulo NPM:

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

Godere!

Tutte queste “directory di root” hanno principalmente bisogno di risolvere qualche percorso virtuale su un percorso di pila reale, quindi potrebbe essere necessario cercare il path.resolve .

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

Forse puoi provare ad attraversare da __filename fino a trovare un package.json , e decidere che è la directory principale a cui appartiene il tuo file corrente.

Una tecnica che ho trovato utile quando si utilizza express consiste nell’aggiungere quanto segue ad app.js prima che venga impostato uno degli altri percorsi

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

Non è necessario utilizzare le globali e il percorso della directory root è una proprietà dell’object richiesta.

Funziona se il tuo app.js è nella radice del tuo progetto che, per impostazione predefinita, lo è.

In realtà, trovo la soluzione forse banale anche per la maggior parte robusta: basta inserire il seguente file nella directory root del tuo progetto: root-path.js che ha il seguente codice:

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

Io uso questo.

Per il mio modulo chiamato mymodule

var BASE_DIR = __dirname.replace(/^(.*\/mymodule)(.*)$/, '$1')

Crea una funzione in 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')); 

In cima al file principale aggiungere:

 mainDir = __dirname; 

Quindi utilizzalo in qualsiasi file necessario:

 console.log('mainDir ' + mainDir); 
  • mainDir è definito globalmente, se ne hai bisogno solo nel file corrente – usa invece __dirname .
  • il file principale si trova di solito nella cartella principale del progetto e viene chiamato come main.js , index.js , gulpfile.js .

Rendilo 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 

Tre semplici passaggi per risolvere il problema del brutto percorso.

  1. Installa il pacchetto: npm install sexy-require --save
  2. Includere require('sexy-require') una volta nella parte superiore del file dell’applicazione principale.

     require('sexy-require'); const routers = require('/routers'); const api = require('$api'); ... 
  3. Passaggio opzionale La configurazione del percorso può essere definita nel file .paths nella directory principale del progetto.

     $db = /server/database $api-v1 = /server/api/legacy $api-v2 = /server/api/v2 
 process.mainModule.paths .filter(p => !p.includes('node_modules')) .shift() 

Ottieni tutti i percorsi nei moduli principali e filtra quelli con “node_modules”, quindi ottieni il primo elenco di percorsi rimanente. Il comportamento imprevisto non genera errori, solo un undefined .

Funziona bene per me, anche quando chiami ie $ mocha .

Puoi semplicemente aggiungere il percorso della directory root nella variabile Express App e ottenere questo percorso dall’app. Per questo aggiungi app.set('rootDirectory', __dirname); nel tuo file index.js o app.js. E usa req.app.get('rootDirectory') per ottenere il percorso della directory root nel tuo codice.

per ottenere il percorso del file corrente:

definisci in quel file:


     var get_stack = function () {
         var orig = Error.prepareStackTrace;
         Error.prepareStackTrace = function (_, stack) {
             stack di ritorno;
         };
         var err = new Errore;
         Error.captureStackTrace (err, arguments.callee);
         var stack = err.stack;
         Error.prepareStackTrace = orig;
         stack di ritorno;
     };

utilizzo in quel file:


     console.log (get_stack () [0] .getFileName ());

API:
StackTrace

Prova path._makeLong('some_filename_on_root.js');

esempio:

 cons path = require('path'); console.log(path._makeLong('some_filename_on_root.js'); 

Ciò restituirà il percorso completo dalla radice dell’applicazione di nodo (stessa posizione di package.json)