Определите корень проекта из работающего приложения node.js

Есть ли лучший способ, чем process.cwd() определить корневой каталог запущенного процесса node.js? Что-то вроде эквивалента Rails.root, но для node.js. Я ищу что-то, что будет как можно более предсказуемым и надежным.

Ответ 1

Есть несколько способов приблизиться к этому, каждый со своими плюсами и минусами:

require.main.filename

Из http://nodejs.org/api/modules.html:

Когда файл запускается непосредственно из Node, require.main устанавливается в его module. Это означает, что вы можете определить, был ли файл запущен напрямую путем тестирования require.main === module

Поскольку module предоставляет свойство filename (обычно эквивалентное __filename), точку входа текущего приложения можно получить, проверив require.main.filename.

Итак, если вы хотите использовать базовый каталог для своего приложения, вы можете сделать:

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

Плюсы и минусы

Это будет работать большую часть времени, но если вы запускаете приложение с помощью программы запуска, например pm2 или выполняете тесты mocha, этот метод не будет выполнен.

global.X

Node имеет глобальный объект пространства имен с именем global - все, что вы прикрепляете к этому объекту, будет доступно везде в вашем приложении. Итак, в вашем index.js (или app.js или любом другом имени вашего основного файла приложения) вы можете просто определить глобальную переменную:

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

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

Плюсы и минусы

Работает последовательно, но вы должны полагаться на глобальную переменную, что означает, что вы не можете легко повторно использовать компоненты/и т.д.

process.cwd()

Возвращает текущий рабочий каталог. Не является надежным вообще, поскольку он полностью зависит от того, в каком каталоге был запущен процесс от:

$ 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

приложение-корневой путь

Чтобы решить эту проблему, я создал модуль node, называемый app-root-path. Использование прост:

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

Модуль app-root-path использует несколько разных методов для определения корневого пути приложения, принимая во внимание глобально установленные модули (например, если ваше приложение работает в /var/www/, но модуль установлен в ~/.nvm/v0.x.x/lib/node/). Он не будет работать в 100% случаев, но он будет работать в большинстве распространенных сценариев.

Плюсы и минусы

Работает без конфигурации в большинстве случаев. Также предоставляет некоторые дополнительные дополнительные методы удобства (см. Страницу проекта). Самая большая проблема заключается в том, что она не будет работать, если:

  • Вы используете пусковую установку, например pm2
  • И, модуль не установлен внутри вашего приложения node_modules (например, если вы установили его по всему миру)

Вы можете обойти это путем установки переменной окружения APP_ROOT_PATH или путем вызова .setPath() в модуле, но в этом случае вам, вероятно, лучше использовать метод global.

NODE_PATH переменная окружения

Если вы ищете способ определить корневой путь для текущего приложения, одно из вышеперечисленных решений, скорее всего, будет работать лучше всего для вас. Если, с другой стороны, вы надежно пытаетесь решить проблему загрузки модулей приложения, я настоятельно рекомендую изучить экологическую переменную NODE_PATH.

Node Система модулей ищет модули в разных местах. Одно из этих мест - где process.env.NODE_PATH указывает. Если вы установите эту переменную окружения, вы можете require модули со стандартным загрузчиком модулей без каких-либо изменений.

Например, если вы установили NODE_PATH в /var/www/lib, следующее будет работать нормально:

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

Отличный способ сделать это - использовать npm:

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

Теперь вы можете запустить свое приложение с помощью npm start, и вы стали золотым. Я совмещаю это с модулем enforce-node-path, который предотвращает случайную загрузку приложения без NODE_PATH. Для еще большего контроля за соблюдением переменных среды см. checkenv.

Один из них: NODE_PATH должен быть установлен вне приложения node. Вы не можете сделать что-то вроде process.env.NODE_PATH = path.resolve(__dirname), потому что загрузчик модуля кэширует список каталогов, которые он будет выполнять до запуска вашего приложения.

[добавлен 4/6/16] Еще один очень перспективный модуль, который пытается решить эту проблему, wavy.

Ответ 2

__dirname не является глобальным; он локален для текущего модуля, поэтому каждый файл имеет свое локальное, другое значение.

Если вам нужен корневой каталог запущенного процесса, вы, вероятно, захотите использовать process.cwd().

Если вам нужна предсказуемость и надежность, то, вероятно, вам необходимо сделать это требование вашего приложения, чтобы была установлена ​​определенная переменная среды. Ваше приложение ищет MY_APP_HOME (или что-то другое), и если оно есть, и приложение существует в этом каталоге, тогда все будет хорошо. Если это undefined или каталог не содержит ваше приложение, он должен выйти с ошибкой, предлагающей пользователю создать переменную. Он может быть установлен как часть процесса установки.

Вы можете прочитать переменные окружения в node с чем-то вроде process.env.MY_ENV_VARIABLE.

Ответ 3

1- создать файл в корне проекта, вызвать его settings.js

2- внутри этого файла добавить этот код

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

3- внутри node_modules создать новое имя модуля, это "настройки", а внутри модуля index.js записать этот код:

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

4- и в любое время, когда вы хотите, чтобы ваш каталог проекта использовал только

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

таким образом у вас будут все каталоги проектов относительно этого файла;)

Ответ 4

самый простой способ получить глобальный корень (при условии, что вы используете NPM для запуска вашего приложения node.js "npm start" и т.д.)

var appRoot = process.env.PWD;

Если вы хотите перекрестно проверить вышеуказанные

Предположим, вы хотите перекрестно проверить process.env.PWD с настройками вашего приложения node.js. если вы хотите, чтобы некоторые тесты времени выполнения проверяли достоверность process.env.PWD, вы можете перекрестно проверить его с помощью этого кода (который я написал, который, кажется, работает хорошо). Вы можете перекрестно проверить имя последней папки в appRoot с именем npm_package_ в файле package.json, например:

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

вы также можете использовать этот модуль NPM: require('app-root-path'), который работает очень хорошо для этой цели

Ответ 5

Я нашел, что это работает для меня последовательно, даже когда приложение вызывается из подпапки, как это может быть с некоторыми тестовыми фреймворками, такими как Mocha:

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

Почему это работает:

На узле выполнения создается реестр полных путей для всех загруженных файлов. Сначала загружаются модули и, таким образом, в верхней части этого реестра. Выбрав первый элемент реестра и вернув путь до каталога "node_modules", мы можем определить корень приложения.

Это всего лишь одна строка кода, но для простоты (ради меня) я черным помещал ее в модуль NPM:

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

Наслаждайтесь!

Ответ 6

Все эти "корневые директории" в основном должны решить какой-то виртуальный путь к реальному пути свай, так что вы можете посмотреть на path.resolve?

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

Ответ 7

Возможно, вы можете попробовать перейти вверх от __filename, пока не найдете package.json, и решите, что основной каталог принадлежит вашему текущему файлу.

Ответ 8

На самом деле, я нахожу, возможно, тривиальное решение также наиболее надежным: просто добавьте следующий файл в корневой каталог вашего проекта: root-path.js, который имеет следующий код:

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

Ответ 9

Метод, который я нашел полезным при использовании экспресс, заключается в добавлении следующего в app.js до того, как будут установлены другие ваши маршруты.

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

app.use('/myroute', myRoute);

Не нужно использовать глобальные переменные, и у вас есть путь к корневому каталогу как свойство объекта запроса.

Это работает, если ваш app.js находится в корне вашего проекта, который по умолчанию это.

Ответ 10

Я знаю, что это уже слишком поздно. Но мы можем получить корневой URL двумя способами

1-й метод

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

Второй метод

var path = require('path');
path.dirname(process.mainModule.filename);

Ссылка ссылки: - https://gist.github.com/geekiam/e2e3e0325abd9023d3a3

Ответ 11

Просто добавьте эту строку в свой модуль в корне, обычно это app.js

global.__basedir = __dirname;

Тогда _basedir будет доступен для всех ваших модулей.

Ответ 12

В верхней части основного файла добавьте:

mainDir = __dirname;

Затем используйте его в любом файле, который вам нужен:

console.log('mainDir ' + mainDir);
  • mainDir определяется глобально, если он вам нужен только в текущем файле - вместо этого используйте __dirname. Основной файл
  • обычно находится в корневой папке проекта и имеет название main.js, index.js, gulpfile.js.

Ответ 13

Я использую это.

Для моего модуля с именем mymodule

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

Ответ 14

Сделайте его сексуальным 💃🏻.

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


Три простых шага для решения проблемы уродливого пути.

  1. Установите пакет: npm install sexy-require --save
  2. Включите require('sexy-require') один раз в верхней части основного файла приложения.

    require('sexy-require');
    const routers = require('/routers');
    const api = require('$api');
    ...
    
  3. Необязательный шаг. Конфигурация пути может быть определена в файле .paths в корневой директории вашего проекта.

    $db = /server/database
    $api-v1 = /server/api/legacy
    $api-v2 = /server/api/v2
    

Ответ 15

Добавьте это где-нибудь к началу основного файла приложения (например, app.js):

global.__basedir = __dirname;

Это задает глобальную переменную, которая всегда будет эквивалентна базовому каталогу вашего приложения. Используйте его так же, как и любую другую переменную:

const yourModule = require(__basedir + '/path/to/module.js');

Просто...

Ответ 16

Создать функцию в 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'));

Ответ 17

process.mainModule.paths
  .filter(p => !p.includes('node_modules'))
  .shift()

Получите все пути в основных модулях и отфильтруйте их с помощью "node_modules", а затем получите первый из оставшихся списков путей. Неожиданное поведение не будет вызывать ошибку, просто undefined.

Хорошо работает для меня, даже при вызове ie $ mocha.

Ответ 18

Вы можете просто добавить корневой путь каталога в переменной экспресс-приложения и получить этот путь из приложения. Для этого добавьте app.set('rootDirectory', __dirname); в файле index.js или app.js. И используйте req.app.get('rootDirectory') для получения корневого каталога в вашем коде.

Ответ 19

Старый вопрос, я знаю, однако не стоит упоминать, как использовать progress.argv. Массив argv включает полное имя пути и имя файла (с расширением.js или без него), который использовался как параметр, который должен выполняться узлом. Поскольку это также может содержать флаги, вы должны отфильтровать это.

Это не пример, который вы можете использовать напрямую (из-за использования моей собственной структуры), но я думаю, что это дает вам некоторое представление о том, как это сделать. Я также использую метод кэширования, чтобы избежать того, что вызов этой функции слишком сильно влияет на систему, особенно если не указано расширение (и существует проверка наличия файла), например:

node myfile

или же

node myfile.js

Это причина, по которой я кешу, см. Также код ниже.


function getRootFilePath()
{
        if( !isDefined( oData.SU_ROOT_FILE_PATH ) )
        {
            var sExt = false;

            each( process.argv, function( i, v )
            {
                 // Skip invalid and provided command line options
                if( !!v && isValidString( v ) && v[0] !== '-' )
                {
                    sExt = getFileExt( v );

                    if( ( sExt === 'js' ) || ( sExt === '' && fileExists( v+'.js' )) )
                    {

                        var a = uniformPath( v ).split("/"); 

                         // Chop off last string, filename
                        a[a.length-1]='';

                         // Cache it so we don't have to do it again.
                        oData.SU_ROOT_FILE_PATH=a.join("/"); 

                         // Found, skip loop
                        return true;
                    }
                }
            }, true ); // <-- true is: each in reverse order
        }

        return oData.SU_ROOT_FILE_PATH || '';
    }
}; 

Ответ 20

Поиск корневого пути электронного приложения может быть сложным. Поскольку корневой путь для основного процесса и средства визуализации различен в разных условиях, таких как условия производства, разработки и пакетирования.

Я написал пакет электрон-корень пакета npm для захвата корневого пути электронного приложения.

$ npm install electron-root-path

or 

$ yarn add electron-root-path


// Import ES6 way
import { rootPath } from 'electron-root-path';

// Import ES2015 way
const rootPath = require('electron-root-path').rootPath;

// e.g:
// read a file in the root
const location = path.join(rootPath, 'package.json');
const pkgInfo = fs.readFileSync(location, { encoding: 'utf8' });

Ответ 21

Это будет делать:

path.join(...process.argv[1].split(/\/|\\/).slice(0, -1))

Ответ 22

Я рассмотрел все предложенные здесь решения, но ни одно из них не помогло, так что вот решение.

Предположим, вам нужен файл config.js, присутствующий в корневом каталоге вашего проекта в файле, который присутствует в /routes/api/users/profile.js, вы не хотите импортировать его как ../../../config.js

  1. Создайте структуру каталогов в корневом каталоге вашего проекта, как описано ниже:
    • /модули
      • index.js
      • package.json
  2. Модули /index.js
    module.exports.config = require('../config.js')
    
  3. Модули /package.js
    {
        "name": "modules",
        "main": "index.js",
        "version": "1.0.0",
        "dependencies": {}
    }
    
  4. Теперь беги
    npm install ./Modules
    
  5. /routes/api/users/profile.js
    const { config } = require('modules')
    

Таким образом, функция автозаполнения вашего редактора кода также будет работать. Нет больше загрязнения глобальных переменных, длинного относительного импорта, никакой зависимости от переменных среды и, что самое приятное, он будет работать с pm2 и nodemon.

Ответ 23

В process.env есть свойство INIT_CWD. Это то, с чем я сейчас работаю в своем проекте.

const {INIT_CWD} = process.env; // process.env.INIT_CWD 
const paths = require('${INIT_CWD}/config/paths');

Удачи...

Ответ 24

Попробуйте path._makeLong('some_filename_on_root.js');

Пример:

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

Это вернет полный путь из корня вашего приложения node (то же самое положение package.json)

Ответ 25

Просто используйте:

 path.resolve("./") ... output is your project root directory

Ответ 26

чтобы получить текущий путь к файлу:

определите в этом файле:

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

в этом файле:

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

API:
StackTrace

Ответ 27

__dirname даст вам корневой каталог, если вы находитесь в файле, который находится в корневом каталоге.

// ProjectDirectory.js (this file is in the project root directory because you are putting it there).
module.exports = {

    root() {
        return __dirname;
    }
}

В каком-то другом файле:

const ProjectDirectory = require('path/to/ProjectDirectory');
console.log('Project root directory is ${ProjectDirectory.root}');