Wie kann ich in node.JS den Pfad eines Moduls abrufen, über das ich geladen habe? Dies ist * nicht * mein (dh in einigen node_module)


92

Ich benötige ein Modul, das über npm installiert wurde. Ich möchte auf eine diesem Modul untergeordnete .js-Datei zugreifen (damit ich eine Konstruktormethode darin unterordnen kann). Ich kann den Code des Moduls nicht ändern (möchte es auch nicht), habe also keinen Platz, um seinen __dirname zu extrahieren.

Mir ist die folgende Frage bekannt, aber es geht darum, den Pfad eines Moduls zu ermitteln, über das Code-Kontrolle besteht (daher ist __dirname die Lösung): Wie kann ich in Node.js den Pfad dieses Moduls ermitteln?

~~~

Noch besser wäre es, die geladenen Modulinformationen des Moduls abzurufen


Wo können Sie das Modul ohne Fehler mit require ('modulename') laden?
Futur

kannst du es besser erklären irgendeinen Code?
Gabriel Llamas

Antworten:


126

Wenn ich Ihre Frage richtig verstehe, sollten Sie require.resolve () verwenden :

Verwenden Sie die interne require () -Maschine, um die Position eines Moduls zu ermitteln. Geben Sie jedoch nicht den geladenen Dateinamen zurück, anstatt das Modul zu laden.

Beispiel: var pathToModule = require.resolve('module');


13
Diese Antwort funktioniert nicht mit allen Knotenmodulen zuverlässig. Siehe meine Antwort.
Jason

55

require.resolve () ist eine Teilantwort. Die akzeptierte Antwort funktioniert möglicherweise für viele Knotenmodule, jedoch nicht für alle.

require.resolve("moduleName")gibt Ihnen nicht das Verzeichnis an, in dem das Modul installiert ist; Sie erhalten den Speicherort der Datei, die im mainAttribut des Moduls definiert ist package.json.

Das könnte sein moduleName/index.jsoder es könnte sein moduleName/lib/moduleName.js. Im letzteren Fall path.dirname(require.resolve("moduleName"))wird ein Verzeichnis zurückgegeben, das Sie möglicherweise nicht möchten oder erwarten:node_modules/moduleName/lib

Der korrekte Weg, um den vollständigen Pfad zu einem bestimmten Modul zu erhalten, besteht darin, den Dateinamen aufzulösen:

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

Wenn Sie nur das Verzeichnis für das Modul möchten (möglicherweise werden Sie viele path.join()Aufrufe tätigen), lösen Sie das package.json- das sich immer im Stammverzeichnis des Projekts befinden muss - auf und übergeben Sie es an path.dirname():

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

1
sehr kluge Antwort, indem man die package.jsonDatei erkennt . Sollten Sie nicht verwenden, path.join('moduleName', 'package.json')um Windows-kompatibel zu sein?
João Pimentel Ferreira

2
@ JoãoPimentelFerreira require.resolveist plattformunabhängig, genauso wie requirees nicht benötigt wirdpath.join
Gopikrishna S

Vergessen Sie nicht, const path = require('path');vor der Verwendung hinzuzufügen path.dirname.
GOTO 0

Ich wünschte, diese Antwort wäre völlig wahr! Ich kann so etwas erfolgreich lösen, require.resolve('@scope/module')was mir so etwas gibt. /path/to/@scope/module/dist/index.jsWenn ich jedoch versuche, es auszuführen require.resolve('@scope/module/package.json'), wird ein MODULE_NOT_FOUNDFehler ausgegeben. Ich bin in Knoten 14.4.0 und das Modul, das ich auflösen "type": "module"möchte , hat in seiner package.json ein exportsFeld, das nicht enthalten ist package.json. Ich bin mir nicht sicher, ob das etwas damit zu tun hat ...
trusktr

Ich habe das Problem gefunden: Wenn ein Modul hat type: module, muss anscheinend package.jsonexplizit im exportsFeld ausgesetzt werden. Ich dachte, dass die neue ESM-Funktion von Node das requireAuflösen von Pfaden nicht wie gewohnt blockiert , aber offensichtlich.
trusktr

3

FYI, require.resolvegibt die Modulkennung gemäß CommonJS zurück. In node.js ist dies der Dateiname. Im Webpack ist dies eine Zahl.

In einer Webpack- Situation ist hier meine Lösung, um den Modulpfad herauszufinden:

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]);

Dann __webpack_modules__[pathToModule]bekam ich Informationen wie diese:

(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?");

    /***/
})

Es stellte sich heraus, dass ich alte Skripte aus der vorherigen DLL-Build-Datei benötigte (für eine schnellere Build-Geschwindigkeit), damit meine aktualisierte Moduldatei nicht wie erwartet funktionierte. Schließlich habe ich meine DLL-Datei neu erstellt und mein Problem gelöst.

Ref: Verwenden require.resolve, um den aufgelösten Dateipfad (Knoten) abzurufen


2

Ich hoffe, ich verstehe Ihre Bedürfnisse richtig: um die Einstiegspunktdatei eines Moduls zu erhalten. Angenommen, Sie möchten den Einstiegspunkt des jugglingdbModuls erhalten:

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

Wie Sie sehen, ist dies kein "offizieller" Weg, um diese Art von Informationen über das Modul zu erhalten. Daher kann sich das Verhalten dieser Funktion von Version zu Version ändern. Ich habe es in der Knotenquelle gefunden: https://github.com/joyent/node/blob/master/lib/module.js#L280


2

Laut @ anatoliy-Lösung hat On MacOS XI die Suchpfade gefunden

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

So erhalte ich die aufgelösten Suchpfade

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

während die

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

wird das Modul, nach dem ich gesucht habe, sowieso nicht auflösen, in der Tat ist das Verrückte, dass _loaddas Modul nicht aufgelöst wird:

> 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)

während der requireWille:

> require('myModule')

aber ich habe dieses Modul nicht in

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/

also wo ist dieses modul ???

Zuerst musste ich eine machen $ sudo /usr/libexec/locate.updatedb Dann nach einem Kaffee machte ich locate myModuleoder besserlocate myModule/someFile.js

et voilà, es stellt sich heraus, dass es sich in einem übergeordneten Ordner meines Projekts befand, dh außerhalb meines Projektstammordners:

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

Sie können es also nicht vermeiden rm -rf ../../node_modules/myModule/ und ein frisches npm install.

Ich kann argumentieren, dass niemand angewiesen hat npm, meinen Computer bei der Suche nach Modulen zu scannen , die nicht in meinem Projektstammordner liegen, in dem er ausgeführt werden sollte, oder im Suchpfad für Standardmodule.


1

Dies ist vielleicht das, wonach Sie suchen. Überprüfen Sie:

require.main.filename


1

Jasons Antwort war die beste Antwort, bis Node.js ESM und das exportsFeld herauskamen.

Jetzt, da Node Pakete mit einem exportsFeld unterstützt, das standardmäßig verhindert, dass Dateien wie aufgelöst werden können, package.jsones sei denn, der Paketautor entscheidet sich ausdrücklich dafür, sie verfügbar zu machen, schlägt der Trick in Jasons Antwort für Pakete fehl, die nicht explizit verfügbar gemacht werden package.json.

Es gibt ein Paket namens resolve-package-path, das den Trick macht.

So verwenden Sie es:

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

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

das wird so etwas ausgeben

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

unabhängig davon, was das exportsFeld des Pakets enthält.


Ich vermute, dass Sie, sobald ein Autor einen Teil des Inhalts des Moduls bewusst exportiert, noch wackeliger sind, da der Autor nun seine öffentliche Schnittstelle formell definiert hat. Ich denke, das würde tendenziell zu einer aggressiveren Umgestaltung von Dingen führen, die nicht explizit exportiert werden, nicht wahr?
Jason

@Jason Das gilt für die Quelldateien, aber die package.json-Dateien verschwinden nicht. Ich sehe keinen Grund, warum diese vor dem Import verborgen sein sollten.
trusktr vor
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.