Bestem prosjektrot fra en kjørende node.js-applikasjon

Er det en bedre måte enn process.cwd() for å bestemme rotkatalogen til en kjørende node.js-prosess? Noe som tilsvarer Rails.root, men for Node.js. Jeg leter etter noe som er så forutsigbart og pålitelig som mulig.

Løsning

Det er flere måter å tilnærme seg dette på, hver med sine egne fordeler og ulemper:

require.main.filename

Fra :

Når en fil kjøres direkte fra Node, settes require.main til dens module. Det betyr at du kan finne ut om en fil har blitt kjørt direkte ved å teste require.main === module.

Fordi module gir en filename-egenskap (normalt ekvivalent med __filename), kan inngangspunktet for den aktuelle applikasjonen fås ved å sjekke require.main.filename.

Så hvis du vil ha basekatalogen for appen din, kan du gjøre det:

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

Fordeler og ulemper

Dette vil fungere bra mesteparten av tiden, men hvis du kjører appen din med en launcher som pm2 eller kjører mocha-tester, vil denne metoden mislykkes.

global.X

Node har et globalt navneromsobjekt kalt global - alt du legger til dette objektet vil være tilgjengelig overalt i appen din. Så, i din index.js (eller app.js eller hva din viktigste app-fil heter), kan du bare definere en global variabel:

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

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

Fordeler og ulemper

Fungerer konsekvent, men du må stole på en global variabel, noe som betyr at du ikke enkelt kan gjenbruke komponenter osv.

process.cwd()

Dette returnerer gjeldende arbeidskatalog. Ikke pålitelig i det hele tatt, da det er helt avhengig av hvilken katalog prosessen ble startet fra:

$ 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

For å løse dette problemet har jeg opprettet en node-modul kalt app-root-path. Bruken er enkel:

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

Modulen app-root-path bruker flere forskjellige teknikker for å bestemme rotbanen til appen, og tar hensyn til globalt installerte moduler (for eksempel hvis appen din kjører i /var/www/, men modulen er installert i ~/.nvm/v0.x.x/lib/node/). Det vil ikke fungere 100 % av tiden, men det vil fungere i de fleste vanlige scenarier.

Fordeler og ulemper

Fungerer uten konfigurasjon i de fleste tilfeller. Gir også noen fine ekstra bekvemmelighetsmetoder (se prosjektsiden). Den største ulempen er at det ikke vil fungere hvis:

  • Du' bruker en bærerakett, som pm2
  • og, modulen ikke er installert i appens node_modules-katalog (for eksempel hvis du installerte den globalt).

Du kan omgå dette ved enten å sette en APP_ROOT_PATH miljøvariabel, eller ved å kalle .setPath() på modulen, men i så fall er det sannsynligvis bedre å bruke global-metoden.

NODE_PATH miljøvariabel

Hvis du leter etter en måte å bestemme rotbanen til den nåværende appen, vil en av løsningene ovenfor sannsynligvis fungere best for deg. Hvis du derimot prøver å løse problemet med å laste inn appmoduler på en pålitelig måte, anbefaler jeg på det sterkeste å se på miljøvariabelen NODE_PATH.

Node&# 39s Modulesystem ser etter moduler på en rekke steder. Ett av disse stedene er der process.env.NODE_PATH peker. Hvis du angir denne miljøvariabelen, kan du "kreve" moduler med standard modullaster uten andre endringer.

Hvis du for eksempel setter NODE_PATH til /var/www/lib, vil følgende fungere helt fint:

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

En god måte å gjøre dette på er å bruke npm:

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

Nå kan du starte appen din med npm start, og du er gull. Jeg kombinerer dette med min enforce-node-path modul, som forhindrer utilsiktet lasting av appen uten NODE_PATH satt. For enda mer kontroll over håndheving av miljøvariabler, se checkenv.

One gotcha: NODE_PATH settes utenfor node-appen. Du kan ikke gjøre noe som process.env.NODE_PATH = path.resolve(__dirname) fordi modullasteren bufrer listen over kataloger den vil søke i før appen din kjøres.

[lagt til 4/6/16] En annen virkelig lovende modul som forsøker å løse dette problemet er wavy.

Kommentarer (22)

__dirname er ikke global; den er lokal for den aktuelle modulen, slik at hver fil har sin egen lokale, forskjellige verdi.

Hvis du vil ha rotkatalogen til den kjørende prosessen, vil du sannsynligvis bruke process.cwd().

Hvis du vil ha forutsigbarhet og pålitelighet, må du sannsynligvis gjøre det til et krav for applikasjonen din at en bestemt miljøvariabel er angitt. Appen din ser etter MY_APP_HOME (eller hva som helst), og hvis den er der, og applikasjonen finnes i den katalogen, er alt i orden. Hvis den er udefinert eller katalogen ikke inneholder applikasjonen din, skal den avslutte med en feil som ber brukeren om å opprette variabelen. Det kan settes som en del av en installasjonsprosess.

Du kan lese miljøvariabler i node med noe sånt som process.env.MY_ENV_VARIABLE.

Kommentarer (2)

1- opprett en fil i prosjektroten, kall den settings.js.

2- inne i denne filen legger du til denne koden

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

3- inne i node_modules oppretter du en ny modul med navnet "settings" og inne i modulen index.js skriver du denne koden:

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

4- og når som helst du vil ha prosjektkatalogen din, bare bruk

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

på denne måten vil du ha alle prosjektkataloger i forhold til denne filen ;)

Kommentarer (9)