Bepaal de project root van een draaiende node.js applicatie

Is er een betere manier dan process.cwd() om de root directory van een draaiend node.js proces te bepalen? Zoiets als het equivalent van Rails.root, maar dan voor Node.js. Ik'ben op zoek naar iets dat zo voorspelbaar en betrouwbaar mogelijk is.

Oplossing

Er zijn verschillende manieren om dit aan te pakken, elk met hun eigen voor- en nadelen:

require.main.filename

Van :

Als een bestand rechtstreeks vanuit Node wordt uitgevoerd, wordt require.main ingesteld op zijn module. Dat betekent dat je kunt bepalen of een bestand direct is uitgevoerd door require.main === module te testen

Omdat module een filename eigenschap heeft (normaal gesproken equivalent aan __filename), kan het startpunt van de huidige applicatie worden verkregen door require.main.filename te controleren.

Dus als je de basisdirectory voor je app wilt, kun je doen:

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

Voors & tegens

Dit zal meestal goed werken, maar als u uw app met een launcher zoals pm2 uitvoert of mocha tests uitvoert, zal deze methode falen.

global.X

Node heeft een globaal namespace object genaamd global - alles wat je aan dit object koppelt zal overal in je app beschikbaar zijn. Dus, in je index.js (of app.js of hoe je hoofd app bestand ook heet), kun je gewoon een globale variabele definiëren:

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

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

Voors & tegens

Werkt consistent, maar je moet vertrouwen op een globale variabele, wat betekent dat je componenten/etc. niet gemakkelijk kunt hergebruiken.

process.cwd()

Dit geeft de huidige werkdirectory terug. Helemaal niet betrouwbaar, omdat het volledig afhangt van vanuit welke directory het proces gestart is vanuit:

$ 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

Om dit probleem aan te pakken, heb ik'een node-module gemaakt genaamd app-root-path. Het gebruik is eenvoudig:

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

De app-root-path module gebruikt verschillende technieken om het root pad van de app te bepalen, rekening houdend met globaal geïnstalleerde modules (bijvoorbeeld, als je app draait in /var/www/ maar de module is geïnstalleerd in ~/.nvm/v0.x.x/lib/node/). Het zal'niet 100% van de tijd werken, maar het'gaat werken in de meest voorkomende scenario's.

Voors & tegens

Werkt zonder configuratie in de meeste omstandigheden. Biedt ook een aantal leuke extra gemaksmethoden (zie projectpagina). Het grootste nadeel is dat het niet zal werken als:

  • U're een launcher gebruikt, zoals pm2
  • En, de module niet geïnstalleerd is in je app's node_modules directory (bijvoorbeeld, als je het globaal geïnstalleerd hebt)

U kunt dit omzeilen door ofwel een APP_ROOT_PATH omgevingsvariabele in te stellen, of door .setPath() op de module aan te roepen, maar in dat geval bent u waarschijnlijk beter af met de global methode.

NODE_PATH omgevingsvariabele

Als je'op zoek bent naar een manier om het root pad van de huidige app te bepalen, zal een van de bovenstaande oplossingen waarschijnlijk het beste voor je werken. Als, aan de andere kant, u'het probleem van het betrouwbaar laden van app modules probeert op te lossen, raad ik u ten zeerste aan de NODE_PATH omgevingsvariabele te onderzoeken.

Node's Modules system zoekt naar modules in een verscheidenheid van locaties. Een van deze locaties is waar process.env.NODE_PATH naar wijst. Als u deze omgevingsvariabele instelt, dan kunt u modules requireen met de standaard module loader zonder andere wijzigingen.

Bijvoorbeeld, als u NODE_PATH instelt op /var/www/lib, dan zou het volgende prima werken:

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

Een goede manier om dit te doen is door npm te gebruiken:

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

Nu kun je je app starten met npm start en je'bent goud waard. Ik combineer dit met mijn enforce-node-path module, die voorkomt dat per ongeluk de app geladen wordt zonder NODE_PATH ingesteld. Voor nog meer controle over het afdwingen van omgevingsvariabelen, zie checkenv.

Eén probleem: NODE_PATH moet worden ingesteld buiten de node app. Je kunt niet iets doen als process.env.NODE_PATH = path.resolve(__dirname) omdat de module loader de lijst van mappen die het zal doorzoeken in een cache opslaat voordat je app draait.

[toegevoegd 4/6/16] Een andere echt veelbelovende module die dit probleem probeert op te lossen is wavy.

Commentaren (22)

__dirname is niet globaal; het is lokaal voor de huidige module, dus elk bestand heeft zijn eigen lokale, verschillende waarde.

Als je de root directory van het lopende proces wilt, wil je waarschijnlijk wel process.cwd() gebruiken.

Als je voorspelbaarheid en betrouwbaarheid wilt, dan moet je waarschijnlijk een eis stellen aan je applicatie dat een bepaalde omgevingsvariabele is ingesteld. Je app zoekt naar MY_APP_HOME (Of wat dan ook) en als die er is, en de applicatie bestaat in die directory, dan is alles goed. Als het niet gedefinieerd is of de map bevat uw toepassing niet dan zou het moeten afsluiten met een fout die de gebruiker vraagt om de variabele te creëren. Het zou kunnen worden ingesteld als onderdeel van een installatieproces.

Je kunt omgevingsvariabelen in node lezen met iets als process.env.MY_ENV_VARIABLE.

Commentaren (2)

1- maak een bestand aan in de project root noem het settings.js

2- voeg in dit bestand de volgende code toe

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

3- binnen node_modules maak een nieuwe module aan noem het "settings" en binnen de module index.js schrijf deze code:

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

4- en elke keer dat u uw project directory wilt gebruiken gewoon

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

op deze manier heb je alle project directories relatief aan dit bestand ;)

Commentaren (9)