W node.JS jak mogę uzyskać ścieżkę do modułu, który załadowałem za pomocą wymagania, które jest * nie * moje (tj. W jakimś module node_module)


94

Potrzebuję modułu, który został zainstalowany przez npm. Chcę uzyskać dostęp do pliku .js podrzędnego do tego modułu (więc mogę podklasować w nim metodę Konstruktora). Nie mogę (cóż, nie chcę) modyfikować kodu modułu, więc nie mam miejsca na wyodrębnienie jego __dirname.

Zdaję sobie sprawę z następującego pytania, ale chodzi o uzyskanie ścieżki do modułu, nad którym ma się kontrolę kodu (stąd rozwiązaniem jest __dirname): W Node.js jak mogę określić ścieżkę do modułu `this`?

~~~

Jeszcze lepiej byłoby uzyskać informacje o załadowanym module


gdzie możesz załadować moduł bez żadnego błędu z require ('modulename')?
Futur

czy możesz to lepiej wyjaśnić? jakiś kod?
Gabriel Llamas

Odpowiedzi:


130

Jeśli dobrze rozumiem Twoje pytanie, użyj require.resolve () :

Użyj wewnętrznego mechanizmu require (), aby znaleźć lokalizację modułu, ale zamiast ładowania modułu, po prostu zwróć rozwiązaną nazwę pliku.

Przykład: var pathToModule = require.resolve('module');


13
Ta odpowiedź nie działa niezawodnie ze wszystkimi modułami węzłów. Zobacz moją odpowiedź.
Jason

61

require.resolve () jest częściową odpowiedzią. Zaakceptowana odpowiedź może działać dla wielu modułów węzłów, ale nie będzie działać dla wszystkich z nich.

require.resolve("moduleName")nie podaje katalogu, w którym moduł jest zainstalowany; podaje lokalizację pliku zdefiniowanego w mainatrybucie w module package.json.

To może być moduleName/index.jslub mogłoby być moduleName/lib/moduleName.js. W tym drugim przypadku path.dirname(require.resolve("moduleName"))zwróci katalog, którego możesz nie chcieć lub oczekiwać:node_modules/moduleName/lib

Prawidłowym sposobem uzyskania pełnej ścieżki do określonego modułu jest rozwiązanie nazwy pliku:

let readmePath = require.resolve("moduleName/README.md");

Jeśli chcesz tylko katalog dla modułu (być może będziesz wykonywać wiele path.join()wywołań), rozwiąż problem package.json- który zawsze musi znajdować się w katalogu głównym projektu - i przekaż do path.dirname():

let packagePath = path.dirname(require.resolve("moduleName/package.json"));

1
bardzo sprytna odpowiedź, poprzez wykrycie package.jsonpliku. Nie powinieneś używać, path.join('moduleName', 'package.json')aby być kompatybilnym z systemem Windows?
João Pimentel Ferreira

2
@ JoãoPimentelFerreira require.resolvejest agnostykiem platformy, tak jak requirewięc nie jest potrzebnypath.join
Gopikrishna S

1
Nie zapomnij dodać const path = require('path');przed użyciem path.dirname.
GOTO 0

Chciałbym, żeby ta odpowiedź była w pełni prawdziwa! Mogę z powodzeniem rozwiązać coś takiego, require.resolve('@scope/module')co daje mi coś podobnego /path/to/@scope/module/dist/index.js, jednak jeśli próbuję uruchomić require.resolve('@scope/module/package.json'), MODULE_NOT_FOUNDwyświetla błąd. Jestem w węźle 14.4.0, a moduł, który próbuję rozwiązać, ma "type": "module"w swoim package.json exportspole, które nie zawiera package.json. Nie jestem pewien, czy to ma z tym coś wspólnego ...
trusktr

Znalazłem problem: kiedy moduł ma type: module, najwyraźniej package.jsonmusi być wyraźnie ujawniony w exportsterenie. Myślałem, że nowa funkcja ESM w Node nie blokuje requirerozwiązywania ścieżek jak zwykle, ale najwyraźniej tak.
trusktr

3

FYI, require.resolvezwraca identyfikator modułu zgodnie z CommonJS. W node.js jest to nazwa pliku. W pakiecie internetowym jest to liczba.

W przypadku webpacka , oto moje rozwiązanie, aby znaleźć ścieżkę modułu:

const pathToModule = require.resolve('module/to/require');
console.log('pathToModule is', pathToModule); // a number, eg. 8
console.log('__webpack_modules__[pathToModule] is', __webpack_modules__[pathToModule]);

Następnie __webpack_modules__[pathToModule]otrzymałem takie informacje:

(function(module, exports, __webpack_require__) {

    eval("module.exports = (__webpack_require__(6))(85);\n\n//////////////////\n// 
    WEBPACK FOOTER\n// delegated ./node_modules/echarts/lib/echarts.js from dll-reference vendor_da75d351571a5de37e2e\n// module id = 8\n// module chunks = 0\n\n//# sourceURL=webpack:///delegated_./node_modules/echarts/lib/echarts.js_from_dll-reference_vendor_da75d351571a5de37e2e?");

    /***/
})

Okazało się, że potrzebowałem starych skryptów z poprzedniego pliku kompilacji dll (dla szybszej kompilacji), więc mój zaktualizowany plik modułu nie działał zgodnie z oczekiwaniami. Wreszcie odbudowałem plik dll i rozwiązałem problem.

Ref: Używanie require.resolvedo uzyskania rozwiązanej ścieżki pliku (węzła)


2

Mam nadzieję, że dobrze rozumiem Twoje potrzeby: uzyskać plik punktu wejścia do jakiegoś modułu. Powiedzmy, że chcesz uzyskać punkt wejścia do jugglingdbmodułu:

node
> require('module')._resolveFilename('jugglingdb')
'/usr/local/lib/node_modules/jugglingdb/index.js'

Jak widać, nie jest to "oficjalny" sposób na uzyskanie tego rodzaju informacji o module, więc zachowanie tej funkcji może się zmieniać z wersji na wersję. Znalazłem to w źródle węzła: https://github.com/joyent/node/blob/master/lib/module.js#L280


2

Zgodnie z rozwiązaniem @anatoliy, na MacOS XI znalazłem ścieżki wyszukiwania

require('module')._resolveLookupPaths('myModule')

więc otrzymuję rozwiązane ścieżki wyszukiwania

[ 'myModule',
  [ '/Users/admin/.node_modules',
    '/Users/admin/.node_libraries',
    '/usr/local/lib/node' ] ]

natomiast

require('module')._resolveFilename('myModule')

i tak nie rozwiąże modułu, którego szukałem, w rzeczywistości szalone jest to, że _loadnie rozwiąże modułu:

> require('module')._load('myModule')
Error: Cannot find module 'myModule'
    at Function.Module._resolveFilename (module.js:440:15)
    at Function.Module._load (module.js:388:25)
    at repl:1:19
    at sigintHandlersWrap (vm.js:32:31)
    at sigintHandlersWrap (vm.js:96:12)
    at ContextifyScript.Script.runInContext (vm.js:31:12)
    at REPLServer.defaultEval (repl.js:308:29)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:489:10)

podczas gdy requirewola:

> require('myModule')

ale nie mam tego modułu w

myProject/node_modules/
myProject/node_modules/@scope/
/usr/local/lib/node_modules/
/usr/local/lib/node_modules/@scope
/usr/local/lib/node_modules/npm/node_modules/
/usr/local/lib/node_modules/npm/node_modules/@scope
$HOME/.npm/
$HOME/.npm/@scope/

więc gdzie jest ten moduł ???

Najpierw musiałem zrobić a $ sudo /usr/libexec/locate.updatedb potem po kawie zrobiłem locate myModulelub lepiejlocate myModule/someFile.js

et voilà, okazuje się, że znajdował się on w folderze nadrzędnym mojego projektu, tj. poza folderem głównym mojego projektu:

$pwd
/Users/admin/Projects/Node/myProject
$ ls ../../node_modules/myModule/

więc nie możesz uniknąć rm -rf ../../node_modules/myModule/i świeżego npm install.

Mogę argumentować, że nikt nie polecił npmprzeskanować mojego komputera w poszukiwaniu modułów w innym miejscu niż folder główny mojego projektu, w którym miał on zostać uruchomiony, lub w domyślnej ścieżce wyszukiwania modułów.


1

Może właśnie tego szukasz, sprawdź:

require.main.filename


1

Odpowiedź Jasona była najlepszą odpowiedzią, dopóki Node.js ESM i exportspole nie wyszły.

Teraz, gdy Node obsługuje pakiety z exportspolem, które domyślnie zapobiega package.jsonrozwiązywaniu plików , chyba że autor pakietu wyraźnie zdecyduje się je ujawnić, sztuczka w odpowiedzi Jasona zakończy się niepowodzeniem w przypadku pakietów, które nie ujawniają jawnie package.json.

Istnieje pakiet o nazwie resolve-package-path, który załatwia sprawę.

Oto jak z niego korzystać:

const resolvePkg = require('resolve-package-path')

console.log(resolvePkg('@some/package'))

który wyświetli coś takiego

/path/to/@some/package/package.json

niezależnie od tego, co exportszawiera pole pakietu .


Podejrzewam, że kiedyś autor świadomie eksportuje część zawartości modułu, to jesteś na jeszcze bardziej chwiejnym gruncie, bo teraz autor formalnie zdefiniował swój publiczny interfejs. Myślę, że prowadziłoby to do bardziej agresywnej refaktoryzacji rzeczy, które nie są bezpośrednio eksportowane, prawda?
Jason

@Jason Dotyczy to plików źródłowych, ale pliki package.json nie znikają. Nie widzę powodu, dla którego powinny być ukryte przed importowaniem.
trusktr
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.