Determinar la raíz del proyecto desde una aplicación Node.js en ejecución

Resuelto MrEvil asked hace 12 años • 34 respuestas

¿Existe alguna forma diferente, además de process.cwd(), de obtener el nombre de ruta del directorio raíz del proyecto actual? ¿Node implementa algo como la propiedad de Ruby Rails.root? Estoy buscando algo que sea constante y confiable.

MrEvil avatar Apr 22 '12 13:04 MrEvil
Aceptado

Hay muchas maneras de abordar esto, cada una con sus pros y sus contras:

require.main.filename

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

Cuando un archivo se ejecuta directamente desde Node, require.mainse establece en su formato module. Eso significa que puede determinar si un archivo se ha ejecutado directamente probandorequire.main === module

Debido a que moduleproporciona una filenamepropiedad (normalmente equivalente a __filename), el punto de entrada de la aplicación actual se puede obtener marcando require.main.filename.

Entonces, si desea el directorio base para su aplicación, puede hacer:

const { dirname } = require('path');
const appDir = dirname(require.main.filename);

Pros contras

Esto funcionará muy bien la mayor parte del tiempo, pero si ejecuta su aplicación con un iniciador como pm2 o ejecuta pruebas de mocha , este método fallará. Esto tampoco funcionará cuando se utilizan módulos Node.js ES, donde require.mainno está disponible.

module.paths

Node publica todas las rutas de búsqueda de módulos en module.paths. Podemos recorrerlos y elegir el primero que se resuelva.

async function getAppPath() {
  const { dirname } = require('path');
  const { constants, promises: { access } } = require('fs');
  
  for (let path of module.paths) {
    try {
      await access(path, constants.F_OK);
      return dirname(path);
    } catch (e) {
      // Just move on to next path
    }
  }
}

Pros contras

Esto algunas veces funcionará, pero no es confiable cuando se usa en un paquete porque puede devolver el directorio en el que está instalado el paquete en lugar del directorio en el que está instalada la aplicación.

Usando una variable global

Node tiene un objeto de espacio de nombres global llamado global: cualquier cosa que adjunte a este objeto estará disponible en todas partes de su aplicación. Entonces, en su index.js(o app.jscomo sea que se llame el archivo de su aplicación principal), puede simplemente definir una variable global:

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

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

Pros contras

Funciona de manera consistente, pero debe confiar en una variable global, lo que significa que no puede reutilizar fácilmente componentes, etc.

process.cwd()

Esto devuelve el directorio de trabajo actual. No es nada confiable, ya que depende completamente del directorio desde el que se inició el proceso :

$ 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

ruta-raíz-aplicación

Para solucionar este problema, creé un módulo de nodo llamado app-root-path . El uso es simple:

const appRoot = require('app-root-path');
const myModule = require(`${ appRoot }/lib/my-module.js`);

El módulo app-root-path utiliza varias técnicas para determinar la ruta raíz de la aplicación, teniendo en cuenta los módulos instalados globalmente (por ejemplo, si su aplicación se está ejecutando /var/www/pero el módulo está instalado en ~/.nvm/v0.x.x/lib/node/). No funcionará el 100% de las veces, pero funcionará en la mayoría de los escenarios comunes.

Pros contras

Funciona sin configuración en la mayoría de las circunstancias. También proporciona algunos métodos convenientes adicionales (consulte la página del proyecto). La mayor desventaja es que no funcionará si:

  • Estás usando un lanzador, como pm2
  • Y , el módulo no está instalado dentro del node_modulesdirectorio de su aplicación (por ejemplo, si lo instaló globalmente)

Puede solucionar esto configurando una APP_ROOT_PATHvariable ambiental o llamando .setPath()al módulo, pero en ese caso, probablemente sea mejor usar el globalmétodo.

Variable ambiental NODE_PATH

Si está buscando una manera de determinar la ruta raíz de la aplicación actual, es probable que una de las soluciones anteriores funcione mejor para usted. Si, por otro lado, estás intentando resolver el problema de cargar módulos de aplicaciones de manera confiable, te recomiendo que investigues la NODE_PATHvariable ambiental.

El sistema de módulos de Node busca módulos en una variedad de ubicaciones. Una de estas ubicaciones es dondequiera que process.env.NODE_PATHapunte . Si configura esta variable ambiental, podrá realizar requiremódulos con el cargador de módulos estándar sin ningún otro cambio.

Por ejemplo, si lo configura NODE_PATHen /var/www/lib, lo siguiente funcionará bien:

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

Una excelente manera de hacer esto es usar npm:

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

Ahora puedes iniciar tu aplicación npm starty listo. Combino esto con mi módulo enforce-node-path , que evita cargar accidentalmente la aplicación sin NODE_PATHconfigurarla. Para obtener aún más control sobre la aplicación de variables ambientales, consulte checkenv .

Un problema: NODE_PATH debe configurarse fuera de la aplicación del nodo. No puede hacer algo así process.env.NODE_PATH = path.resolve(__dirname)porque el cargador de módulos almacena en caché la lista de directorios que buscará antes de que se ejecute su aplicación.

[agregado el 6/04/16] Otro módulo realmente prometedor que intenta resolver este problema es wavy .

inxilpro avatar Sep 10 '2013 14:09 inxilpro

__dirnameno es global; es local para el módulo actual, por lo que cada archivo tiene su propio valor local diferente.

Si desea el directorio raíz del proceso en ejecución, probablemente desee utilizar process.cwd().

Si desea previsibilidad y confiabilidad, entonces probablemente deba establecer como requisito de su aplicación que se establezca una determinada variable de entorno. Su aplicación busca MY_APP_HOME(o lo que sea) y si está allí y la aplicación existe en ese directorio, entonces todo está bien. Si no está definido o el directorio no contiene su aplicación, entonces debería salir con un error que solicita al usuario que cree la variable. Podría configurarse como parte de un proceso de instalación.

Puede leer variables de entorno en el nodo con algo como process.env.MY_ENV_VARIABLE.

izb avatar Jun 07 '2013 15:06 izb

Simple:

require('path').resolve('./')
Vansuita Jr. avatar Jun 14 '2020 20:06 Vansuita Jr.

la forma más fácil de obtener la raíz global ( suponiendo que use NPM para ejecutar su aplicación node.js 'npm start', etc. )

var appRoot = process.env.PWD;

Si desea verificar lo anterior

Supongamos que desea realizar una verificación cruzada process.env.PWDcon la configuración de su aplicación node.js. Si desea realizar algunas pruebas en tiempo de ejecución para verificar la validez de process.env.PWD, puede verificarlo con este código (que escribí y que parece funcionar bien). Puede verificar el nombre de la última carpeta en appRoot con npm_package_name en su archivo package.json, por ejemplo:

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

También puedes usar este módulo NPM: require('app-root-path')que funciona muy bien para este propósito.

Alexander Mills avatar May 26 '2015 18:05 Alexander Mills