Określ katalog główny projektu z działającej aplikacji node.js


315

Czy istnieje lepszy sposób niż process.cwd()określenie katalogu głównego działającego procesu node.js? Coś podobnego do Rails.root, ale dla Node.js. Szukam czegoś, co jest jak najbardziej przewidywalne i niezawodne.


1
Czy jest jakaś szansa, że ​​możesz odrzucić zaakceptowaną, błędną odpowiedź?
Dave Newton,

9
spróbuj process.env.PWD... zobacz moją odpowiedź poniżej.
Alexander Mills

Odpowiedzi:


624

Istnieje kilka sposobów podejścia do tego, każdy z własnymi zaletami i wadami:

wymagają.main.filename

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

Gdy plik jest uruchamiany bezpośrednio z Węzła, require.mainjest ustawiany na jego module. Oznacza to, że możesz ustalić, czy plik został uruchomiony bezpośrednio przez testowanierequire.main === module

Ponieważ modulezapewnia filenamewłaściwość (zwykle równoważną __filename), punkt wejścia bieżącej aplikacji można uzyskać, sprawdzając require.main.filename.

Jeśli więc chcesz katalog podstawowy swojej aplikacji, możesz:

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

Za I przeciw

Będzie to działać wielki większość czasu, ale jeśli używasz aplikacji z wyrzutni jak PM2 lub bieganie mokka testy, ta metoda zawiedzie.

global.X

Węzeł ma nazwany globalny obiekt przestrzeni nazw global- wszystko, co dołączasz do tego obiektu, będzie dostępne wszędzie w Twojej aplikacji. Zatem w swoim index.js(lub app.jsjakimkolwiek innym głównym pliku aplikacji) można po prostu zdefiniować zmienną globalną:

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

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

Za I przeciw

Działa konsekwentnie, ale musisz polegać na zmiennej globalnej, co oznacza, że ​​nie możesz łatwo ponownie użyć komponentów / etc.

process.cwd ()

Zwraca bieżący katalog roboczy. Nie są wiarygodne w ogóle, jak to jest całkowicie zależne od tego, co katalog proces został uruchomiony od :

$ 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

Aby rozwiązać ten problem, utworzyłem moduł węzła o nazwie app-root-path . Użycie jest proste:

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

App-root-path Moduł wykorzystuje kilka różnych technik w celu określenia katalogu głównym aplikacji, z uwzględnieniem modułów zainstalowanych na całym świecie (na przykład, jeśli aplikacja jest uruchomiona w /var/www/ale moduł jest zainstalowany w~/.nvm/v0.x.x/lib/node/ ). Nie będzie działać w 100% przypadków, ale zadziała w większości typowych scenariuszy.

Za I przeciw

Działa bez konfiguracji w większości przypadków. Zapewnia również kilka dodatkowych metod wygody (patrz strona projektu). Największą wadą jest to, że nie zadziała, jeśli:

  • Używasz programu uruchamiającego, takiego jak pm2
  • ORAZ moduł nie jest zainstalowany w node_moduleskatalogu aplikacji (na przykład jeśli zainstalowałeś go globalnie)

Możesz obejść ten problem, ustawiając APP_ROOT_PATHzmienną środowiskową lub wywołując .setPath()moduł, ale w takim przypadku prawdopodobnie lepiej jest użyćglobal metody.

Zmienna środowiskowa NODE_PATH

Jeśli szukasz sposobu na określenie ścieżki katalogu głównego bieżącej aplikacji, prawdopodobnie jedno z powyższych rozwiązań będzie dla Ciebie najlepsze. Jeśli z drugiej strony próbujesz rozwiązać problem z niezawodnym ładowaniem modułów aplikacji, zdecydowanie polecam przyjrzenie się NODE_PATHzmiennej środowiskowej.

System modułów Node szuka modułów w różnych lokalizacjach. Jedna z tych lokalizacji jest wszędzie tam, gdzie są process.env.NODE_PATHpunkty . Jeśli ustawisz tę zmienną środowiskową, możesz requiremoduły ze standardowym modułem ładującym moduły bez żadnych innych zmian.

Na przykład, jeśli ustawisz NODE_PATHdo /var/www/libThe dodaje będzie działać dobrze:

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

Świetnym sposobem na to jest użycie npm:

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

Teraz możesz uruchomić aplikację npm starti jesteś złoty. Łączę to z moim modułem enforce-node-path , który zapobiega przypadkowemu załadowaniu aplikacji bez NODE_PATHustawienia. Aby uzyskać jeszcze większą kontrolę nad wymuszaniem zmiennych środowiskowych, zobacz checkenv .

Jedna gotcha: NODE_PATH musi być ustawiona poza aplikacją node. Nie możesz zrobić czegoś takiego, process.env.NODE_PATH = path.resolve(__dirname)ponieważ moduł ładujący buforuje listę katalogów, które będzie wyszukiwał przed uruchomieniem aplikacji.

[dodano 4/6/16] Kolejny naprawdę obiecujący moduł, który próbuje rozwiązać ten problem, jest falisty .


1
@ Kevin w tym przypadku, mokka jest punktem wejścia do twojej aplikacji. To tylko przykład, dlaczego znalezienie „katalogu głównego projektu” jest tak trudne - zależy tak bardzo od sytuacji i tego, co rozumiesz przez „katalog główny projektu”.
inxilpro

1
@Kevin Całkowicie rozumiem. Chodzi mi o to, że pojęcie „root projektu” jest dla człowieka znacznie łatwiejsze do zrozumienia niż komputer . Jeśli potrzebujesz niezawodnej metody, musisz ją skonfigurować. Korzystanie będzie działać przez większość czasu, ale nie przez cały czas. require.main.filename
inxilpro

2
Stycznie powiązane: jest to niezwykle sprytny sposób na zorganizowanie projektu Node, abyś nie musiał się tak bardzo przejmować tym problemem: allanhortle.com/2015/02/04/…
inxilpro

1
Nie wiem, czy nastąpiła zmiana w pm2 czy zmiana w Node.js, ale require.main.filenamewydaje się, że działa z pm2. Nie wiem o mokce.
Justin Warkentin

8
path.parse(process.mainModule.filename).dir
Cory Robinson

53

__dirnamenie jest globalny; jest lokalny dla bieżącego modułu, więc każdy plik ma swoją lokalną, inną wartość.

Jeśli chcesz katalog główny uruchomionego procesu, prawdopodobnie chcesz go użyć process.cwd().

Jeśli chcesz mieć przewidywalność i niezawodność, prawdopodobnie musisz wprowadzić w aplikacji wymóg ustawiania określonej zmiennej środowiskowej. Twoja aplikacja szuka MY_APP_HOME(lub cokolwiek innego), a jeśli już tam jest, a aplikacja istnieje w tym katalogu, to wszystko jest w porządku. Jeśli jest niezdefiniowany lub katalog nie zawiera aplikacji, powinien zakończyć działanie z błędem monitującym użytkownika o utworzenie zmiennej. Można to ustawić jako część procesu instalacji.

Możesz odczytać zmienne środowiskowe w węźle za pomocą czegoś takiego process.env.MY_ENV_VARIABLE.


2
Przy ostrożnym użyciu może to działać całkiem dobrze. Ale to daje różne wyniki, kiedy robi bin/server.jsvs cd bin && server.js. (zakładając, że te pliki js są oznaczone jako pliki wykonywalne)
Myrne Stol

1
Używanie process.cwd()działało dla mnie jak urok, nawet podczas testów mokki. Dziękuję Ci!
Diogo Eichert

49

1- utwórz plik w katalogu głównym projektu, wywołaj go settings.js

2- wewnątrz tego pliku dodaj ten kod

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

3- wewnątrz modułu node_modules stwórz nowy moduł, który „ustawia”, a wewnątrz modułu index.js napisz ten kod:

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

4- i za każdym razem, gdy chcesz tylko użyć katalogu projektu

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

w ten sposób będziesz mieć wszystkie katalogi projektu dotyczące tego pliku;)


33
-1: Aby załadować plik ustawień, potrzebujesz ścieżki, a następnie uzyskaj ścieżkę referencyjną do tego pliku? Niczego nie rozwiązuje ...
Goliatone

2
Głosowanie za poświęcenie czasu na sprawdzenie i edycję. Nadal wydaje się kruchy, ale może tak być, ponieważ nie ma lepszego sposobu na osiągnięcie tego
goliatone,

8
Przy takim podejściu użytkownicy powinni pamiętać o tym, że node_modulesczęsto są wykluczeni z kontroli wersji. Więc jeśli pracujesz z zespołem lub kiedykolwiek będziesz musiał sklonować swoje repozytorium, będziesz musiał znaleźć inne rozwiązanie, aby utrzymać synchronizację tego pliku ustawień.
Travesty3

@ Travesty3 moduł ustawień jest właściwie pustym modułem, który eksportuje zawartość pliku w katalogu głównym projektu: P
Fareed Alnamrouti

@ Goliatone Dzięki jego rozwiązaniu możesz pobrać plik z dowolnego miejsca, nie znając jego ścieżki, wszystko, co musisz wiedzieć, to „ustawienia”. Bez tego musiałbyś wyraźnie wiedzieć, z ilu folderów wycofać się, aż dojdziesz do katalogu projektu. Działa to, ponieważ węzeł automatycznie przeszukuje moduły węzłów i zawsze wie, gdzie to jest.

26

najłatwiejszy sposób na uzyskanie globalnego katalogu głównego ( zakładając, że używasz NPM do uruchamiania aplikacji node.js „npm start” itp. )

var appRoot = process.env.PWD;

Jeśli chcesz zweryfikować powyższe

Powiedz, że chcesz sprawdzić krzyżowo process.env.PWDz ustawieniami aplikacji node.js. jeśli chcesz, aby niektóre testy środowiska uruchomieniowego sprawdzały poprawność process.env.PWD, możesz sprawdzić to za pomocą tego kodu (który napisałem, który wydaje się działać dobrze). Możesz sprawdzić krzyżowo nazwę ostatniego folderu w appRoot z nazwą npm_package_name w pliku package.json, na przykład:

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

możesz również użyć tego modułu NPM: require('app-root-path')który działa bardzo dobrze w tym celu


5
Działa to świetnie na (większości) systemach uniksowych. Gdy tylko chcesz, aby moduł / aplikacja npm działała w systemie Windows, PWDjest niezdefiniowana i to się nie udaje.
Jeremy Wiebe

1
process.cwd()
Muhammad Umer

@MuhammadUmer, dlaczego process.cwd()zawsze miałby być taki sam jak root projektu?
Alexander Mills,

jeśli nazwiesz go w pliku głównym, będzie to
Muhammad Umer

14

Przekonałem się, że działa to dla mnie konsekwentnie, nawet gdy aplikacja jest wywoływana z podfolderu, podobnie jak w przypadku niektórych środowisk testowych, takich jak Mocha:

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

Dlaczego to działa:

W czasie wykonywania węzeł tworzy rejestr pełnych ścieżek wszystkich załadowanych plików. Moduły są ładowane jako pierwsze, a więc na początku tego rejestru. Wybierając pierwszy element rejestru i zwracając ścieżkę przed katalogiem „node_modules”, jesteśmy w stanie określić katalog główny aplikacji.

To tylko jedna linia kodu, ale dla uproszczenia (na miłość boską) umieściłem go w czarnej skrzynce w module NPM:

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

Cieszyć się!


1
process.mainModule usunięto od: v14.0.0 - użyj require.main.paths[0].split('node_modules')[0].slice(0, -1);zamiast tego.
RobC

10

Wszystkie te „katalogi główne” najczęściej wymagają rozwiązania jakiejś wirtualnej ścieżki do prawdziwej ścieżki stosu, więc może powinieneś się przyjrzeć path.resolve?

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

9

Tak proste, jak dodanie tej linii do modułu w katalogu głównym, zwykle jest to app.js

global.__basedir = __dirname;

Wówczas _basedir będzie dostępny dla wszystkich modułów.


8

Może możesz spróbować przejść w górę od, __filenameaż znajdziesz a package.json, i zdecydować, że jest to główny katalog, do którego należy twój bieżący plik.


7

Właściwie uważam, że trywialne rozwiązanie jest również najbardziej niezawodne: po prostu umieszczasz następujący plik w katalogu głównym swojego projektu: root-path.js, który ma następujący kod:

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

4

Techniką, która okazała się przydatna podczas korzystania z ekspresu, jest dodanie do app.js następujących elementów przed ustawieniem dowolnej innej trasy

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

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

Nie trzeba używać globałów, a ścieżka katalogu głównego jest właściwością obiektu żądania.

Działa to, jeśli plik app.js znajduje się w katalogu głównym projektu, którym jest domyślnie.


4

Dodaj to gdzieś na początku głównego pliku aplikacji (np. App.js):

global.__basedir = __dirname;

Ustawia to zmienną globalną, która zawsze będzie równoważna z podstawowym katalogiem aplikacji. Użyj go tak jak każdej innej zmiennej:

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

Prosty...



3

Jest INIT_CWDwłaściwość na process.env. Z tym obecnie pracuję nad moim projektem.

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

Powodzenia...


1
Działał jak urok pakietu, który manipuluje projektem, z którego jest wywoływany, jako krok po instalacji. Jednak nie przetestowałem go jeszcze w innej warstwie zależności, w której projekt wykorzystuje zależność korzystającą z mojego pakietu.
JamesDev,

1
@JamesDev, INIT_CWDrozwiązuje do tego, directoryz którego npm-scriptwykonano egzekucję.
Akash

2

jeśli chcesz określić katalog główny projektu z działającej aplikacji node.js, możesz po prostu też.

process.mainModule.path

1

Na górze głównego pliku dodaj:

mainDir = __dirname;

Następnie użyj go w dowolnym pliku, którego potrzebujesz:

console.log('mainDir ' + mainDir);
  • mainDirjest zdefiniowany globalnie, jeśli potrzebujesz go tylko w bieżącym pliku - użyj __dirnamezamiast niego.
  • Główny plik jest zazwyczaj w folderze głównym projektu jest nazwany jak main.js, index.js, gulpfile.js.

1

Używam tego.

Dla mojego modułu o nazwie mymodule

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


1

Zrób to seksownie 💃🏻.

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


Trzy proste kroki, aby rozwiązać problem brzydkiej ścieżki.

  1. Zainstaluj pakiet: npm install sexy-require --save
  2. Dołącz require('sexy-require')raz na górze głównego pliku aplikacji.

    require('sexy-require');
    const routers = require('/routers');
    const api = require('$api');
    ...
  3. Opcjonalny krok. Konfigurację ścieżki można zdefiniować w .pathspliku w katalogu głównym projektu.

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

Wydaje się przyzwoite, szkoda, że ​​miało tak absurdalne imię.
JHH,

@ JHH cóż ... Musiałem znaleźć lepsze imię
sułtan

1

Spowoduje to obniżenie drzewa katalogów, aż będzie zawierało node_moduleskatalog, który zwykle wskazuje katalog główny projektu:

const fs = require('fs')
const path = require('path')

function getProjectRoot(currentDir = __dirname.split(path.sep)) {
  if (!currentDir.length) {
    throw Error('Could not find project root.')
  }
  const nodeModulesPath = currentDir.concat(['node_modules']).join(path.sep)
  if (fs.existsSync(nodeModulesPath) && !currentDir.includes('node_modules')) {
    return currentDir.join(path.sep)
  }
  return this.getProjectRoot(currentDir.slice(0, -1))
}

Zapewnia również, że nie ma node_modulesw zwracanej ścieżce, ponieważ oznacza to, że jest ona zawarta w instalacji pakietu zagnieżdżonego.


1

process.mainModulejest przestarzałe od wersji 14.0.0. Odnosząc się do odpowiedzi, proszę użyć require.main , reszta nadal obowiązuje.

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

Uzyskaj wszystkie ścieżki w głównych modułach i odfiltruj je za pomocą „node_modules”, a następnie uzyskaj pierwszą z pozostałych list ścieżek. Nieoczekiwane zachowanie nie spowoduje błędu, tylko undefined.

Działa dla mnie dobrze, nawet podczas dzwonienia tj $ mocha.


0

Utwórz funkcję w 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'));

0

Możesz po prostu dodać ścieżkę katalogu głównego do zmiennej ekspresowej aplikacji i pobrać tę ścieżkę z aplikacji. W tym celu dodaj app.set('rootDirectory', __dirname);do pliku index.js lub app.js. I użyj req.app.get('rootDirectory')do uzyskania ścieżki katalogu głównego w kodzie.


0

Stare pytanie, wiem, ale nie ma wzmianki o użyciu progress.argv. Tablica argv zawiera pełną ścieżkę i nazwę pliku (z rozszerzeniem .js lub bez), który został użyty jako parametr do wykonania przez węzeł. Ponieważ może to również zawierać flagi, musisz to przefiltrować.

Nie jest to przykład, którego możesz użyć bezpośrednio (z powodu użycia własnego frameworka), ale myślę, że daje ci to pewien pomysł, jak to zrobić. Korzystam również z metody pamięci podręcznej, aby uniknąć zbyt dużego obciążenia systemu wywołaniem tej funkcji, zwłaszcza gdy nie podano rozszerzenia (wymagane jest sprawdzenie pliku), na przykład:

node myfile

lub

node myfile.js

To jest powód, dla którego go buforuję, patrz także kod poniżej.


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

0

Znalezienie ścieżki katalogu głównego aplikacji elektronowej może być trudne. Ponieważ ścieżka główna jest inna dla głównego procesu i mechanizmu renderującego w różnych warunkach, takich jak produkcja, programowanie i warunki spakowane.

Napisałem pakiet npm electron-root-root-path, aby przechwycić ścieżkę root aplikacji elektronowej.

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



0

Preambuła

To bardzo stare pytanie, ale wydaje się, że wciąż uderza w nerwy w 2020 r., Jak w 2012 r. Sprawdziłem wszystkie pozostałe odpowiedzi i nie mogłem znaleźć techniki (zauważ, że ma to swoje ograniczenia, ale wszystkie inne nie są dotyczy również każdej sytuacji).

Proces potomny GIT +

Jeśli używasz GIT jako systemu kontroli wersji, problem z określeniem katalogu głównego projektu można zredukować do (który uważam za właściwy katalog główny projektu - w końcu chciałbyś, aby Twój VCS miał możliwie największy zakres widoczności) :

wycofana ścieżka katalogu głównego repozytorium

Ponieważ w tym celu musisz uruchomić komendę CLI, będziemy musieli odrodzić proces potomny. Dodatkowo, ponieważ istnieje duże prawdopodobieństwo, że katalog główny projektu nie zmieni się w czasie wykonywania, możemy użyć synchronicznej wersji child_processinterfejsów API modułów podczas uruchamiania.

Okazało spawnSync()się, że jestem najbardziej odpowiedni do tej pracy. Jeśli chodzi o faktyczne polecenie do uruchomienia, git worktree(z --porcelainopcją łatwego parsowania) wszystko, czego potrzebujemy, aby pobrać bezwzględną ścieżkę root.

W przykładzie zdecydowałem się zwrócić tablicę ścieżek, ponieważ może istnieć więcej niż jedno drzewo robocze (chociaż prawdopodobnie mają one wspólne ścieżki), aby się upewnić. Zauważ, że ponieważ używamy polecenia CLI, shellopcja powinna być ustawiona natrue (bezpieczeństwo nie powinno być problemem, ponieważ nie ma niezaufanych danych wejściowych).

Porównanie podejść i awarie

Rozumiejąc, że sytuacja, w której VCS może być niedostępny, przedstawiłem kilka awarii po przeanalizowaniu dokumentów i innych odpowiedzi. Podsumowując, proponowane rozwiązania sprowadzają się do (z wyjątkiem modułów innych producentów i specyficznych dla pakietu):

| Rozwiązanie | Zaleta | Główny problem |
| ------------------------ | ----------------------- | -------------------------------- |
| `__nazwa_pliku` | wskazuje na plik modułu | względem modułu |
| `__dirname` | wskazuje na moduł reż | taki sam jak `__nazwa_pliku` |
| spacer po drzewie | node_modules` prawie gwarantowany root | złożone chodzenie po drzewie, jeśli jest zagnieżdżone
| `path.resolve (". ")` | root, jeśli CWD to root | to samo co `process.cwd ()` |
| `process.argv [1]` | taki sam jak `__nazwa_pliku` | taki sam jak `__nazwa_pliku` |
| `process.env.INIT_CWD` | wskazuje na „npm run” reż | wymaga uruchomienia `npm` && CLI |
| `process.env.PWD` | wskazuje na bieżący katalog | w odniesieniu do (jest) uruchomienie katalog |
| `process.cwd ()` | to samo co `env.PWD` | `process.chdir (ścieżka)` w czasie wykonywania |
| `wymagają.main.nazwa_pliku` | root, jeśli `=== moduł` | kończy się niepowodzeniem na modułach „need`d”

Z powyższej tabeli porównawczej najbardziej uniwersalne są dwa podejścia:

  • require.main.filenamejako prosty sposób na rootowanie, jeśli require.main === modulezostanie spełniony
  • node_modulesproponowany ostatnio spacer po drzewie opiera się na innym założeniu:

jeśli katalog modułu ma katalog node_moduleswewnątrz, prawdopodobnie jest to katalog główny

W przypadku głównej aplikacji pobierze katalog główny aplikacji, a dla modułu - katalog główny projektu.

Fallback 1. Spacer po drzewie

Moja implementacja używa bardziej swobodnego podejścia, zatrzymując się po znalezieniu katalogu docelowego, ponieważ dla danego modułu jego katalogiem głównym jest katalog główny projektu. Można połączyć połączenia lub rozszerzyć je, aby skonfigurować głębokość wyszukiwania:

/**
 * @summary gets root by walking up node_modules
 * @param {import("fs")} fs
 * @param {import("path")} pt
 */
const getRootFromNodeModules = (fs, pt) =>

    /**
     * @param {string} [startPath]
     * @returns {string[]}
     */
    (startPath = __dirname) => {

        //avoid loop if reached root path
        if (startPath === pt.parse(startPath).root) {
            return [startPath];
        }

        const isRoot = fs.existsSync(pt.join(startPath, "node_modules"));

        if (isRoot) {
            return [startPath];
        }

        return getRootFromNodeModules(fs, pt)(pt.dirname(startPath));
    };

Fallback 2. Moduł główny

Druga implementacja jest banalna

/**
 * @summary gets app entry point if run directly
 * @param {import("path")} pt
 */
const getAppEntryPoint = (pt) =>

    /**
     * @returns {string[]}
     */
    () => {

        const { main } = require;

        const { filename } = main;

        return main === module ?
            [pt.parse(filename).dir] :
            [];
    };

Realizacja

Sugerowałbym użycie chodzika jako rezerwowego, ponieważ jest on bardziej wszechstronny:

const { spawnSync } = require("child_process");
const pt = require('path');
const fs = require("fs");

/**
 * @summary returns worktree root path(s)
 * @param {function : string[] } [fallback]
 * @returns {string[]}
 */
const getProjectRoot = (fallback) => {

    const { error, stdout } = spawnSync(
        `git worktree list --porcelain`,
        {
            encoding: "utf8",
            shell: true
        }
    );

    if (!stdout) {
        console.warn(`Could not use GIT to find root:\n\n${error}`);
        return fallback ? fallback() : [];
    }

    return stdout
        .split("\n")
        .map(line => {
            const [key, value] = line.split(/\s+/) || [];
            return key === "worktree" ? value : "";
        })
        .filter(Boolean);
};

Niedogodności

Najbardziej oczywistym jest zainstalowanie i zainicjowanie GIT, co może być niepożądane / niewiarygodne (uwaga: zainstalowanie GIT na serwerach produkcyjnych nie jest rzadkością ani nie jest niebezpieczne ). Może być zapośredniczony przez awarie, jak opisano powyżej.

Notatki

  1. Kilka pomysłów na dalsze rozszerzenie podejścia 1:
    • wprowadź config jako parametr funkcji
    • export funkcja, aby uczynić go modułem
    • sprawdź, czy GIT jest zainstalowany i / lub zainicjowany

Bibliografia

  1. git worktree odniesienie
  2. spawnSync odniesienie
  3. require.main odniesienie
  4. path.dirname() odniesienie


-1

Próbować path._makeLong('some_filename_on_root.js');

przykład:

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

To zwróci pełną ścieżkę z katalogu głównego aplikacji węzła (ta sama pozycja pliku package.json)


-1

Po prostu użyj:

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

to działa świetnie! path.resolve (".") również działa
Noel Schenk

To daje tylko bieżący katalog, który może nie być katalogiem głównym.
orad

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.