Determinar la raíz del proyecto desde una aplicación Node.js en ejecución
¿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.
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.main
se establece en su formatomodule
. Eso significa que puede determinar si un archivo se ha ejecutado directamente probandorequire.main === module
Debido a que
module
proporciona unafilename
propiedad (normalmente equivalente a__filename
), el punto de entrada de la aplicación actual se puede obtener marcandorequire.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.main
no 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.js
como 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_modules
directorio de su aplicación (por ejemplo, si lo instaló globalmente)
Puede solucionar esto configurando una APP_ROOT_PATH
variable ambiental o llamando .setPath()
al módulo, pero en ese caso, probablemente sea mejor usar el global
mé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_PATH
variable 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_PATH
apunte . Si configura esta variable ambiental, podrá realizar require
módulos con el cargador de módulos estándar sin ningún otro cambio.
Por ejemplo, si lo configura NODE_PATH
en /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 start
y listo. Combino esto con mi módulo enforce-node-path , que evita cargar accidentalmente la aplicación sin NODE_PATH
configurarla. 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 .
__dirname
no 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
.
Simple:
require('path').resolve('./')
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.PWD
con 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.