Dans node.JS, comment puis-je obtenir le chemin d'un module que j'ai chargé via require qui n'est * pas * le mien (c'est-à-dire dans certains node_module)


93

J'ai besoin d'un module qui a été installé via npm. Je veux accéder à un fichier .js subordonné à ce module (afin que je puisse sous-classer une méthode Constructor dedans). Je ne peux pas (enfin, je ne veux pas) modifier le code du module, donc je n'ai pas d'endroit pour extraire son __dirname.

Je suis conscient de la question suivante, mais il s'agit d'obtenir le chemin d'un module sur lequel on a le contrôle du code (par conséquent, __dirname est la solution): Dans Node.js, comment puis-je indiquer le chemin du module `this`?

~~~

Encore mieux serait d'obtenir les informations du module chargé du module


où vous pouvez charger le module sans aucune erreur avec require ('modulename')?
Futur

pouvez-vous mieux l'expliquer? du code?
Gabriel Llamas

Réponses:


127

Si je comprends bien votre question, vous devriez utiliser require.resolve () :

Utilisez la machine interne require () pour rechercher l'emplacement d'un module, mais plutôt que de charger le module, retournez simplement le nom de fichier résolu.

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


13
Cette réponse ne fonctionne pas de manière fiable avec tous les modules de nœuds. Voyez ma réponse.
Jason

57

require.resolve () est une réponse partielle. La réponse acceptée peut fonctionner pour de nombreux modules de nœuds, mais ne fonctionnera pas pour tous.

require.resolve("moduleName")ne vous donne pas le répertoire où le module est installé; il vous donne l'emplacement du fichier défini dans l' mainattribut dans le module package.json.

Cela pourrait être moduleName/index.jsou cela pourrait être moduleName/lib/moduleName.js. Dans ce dernier cas, path.dirname(require.resolve("moduleName"))retournera un répertoire que vous ne voulez ou ne vous attendez pas:node_modules/moduleName/lib

La bonne façon d'obtenir le chemin complet vers un module spécifique est de résoudre le nom de fichier:

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

Si vous voulez juste le répertoire du module (peut-être que vous allez faire beaucoup d' path.join()appels), résolvez le package.json- qui doit toujours être à la racine du projet - et passez à path.dirname():

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

1
réponse très astucieuse, en détectant le package.jsonfichier. Ne devriez-vous pas utiliser path.join('moduleName', 'package.json')pour être compatible avec Windows?
João Pimentel Ferreira

2
@ JoãoPimentelFerreira require.resolveest indépendant de la plate-forme, tout comme requireil n'est pas nécessaire de l'utiliserpath.join
Gopikrishna S

1
N'oubliez pas d'ajouter const path = require('path');avant d'utiliser path.dirname.
GOTO 0

Je souhaite que cette réponse soit pleinement vraie! Je peux résoudre avec succès quelque chose comme require.resolve('@scope/module')ce qui me donne quelque chose comme /path/to/@scope/module/dist/index.js, mais si j'essaie de l'exécuter, require.resolve('@scope/module/package.json')cela génère une MODULE_NOT_FOUNDerreur. Je suis dans Node 14.4.0 et le module que j'essaie de résoudre a "type": "module"dans son package.json avec un exportschamp qui n'inclut pas package.json. Je ne sais pas si cela a quelque chose à voir avec ça ...
trusktr

J'ai trouvé le problème: quand un module a type: module, apparemment, package.jsondoit être explicitement exposé sur le exportsterrain. Je pensais que la nouvelle fonctionnalité ESM de Node n'empêchait pas requirede résoudre les chemins comme d'habitude, mais c'est évident.
trusktr

3

Pour info, require.resolverenvoie l'identifiant du module selon CommonJS. Dans node.js, c'est le nom du fichier. Dans Webpack, c'est un nombre.

En situation webpack , voici ma solution pour connaître le chemin du module:

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

Ensuite, __webpack_modules__[pathToModule]j'ai eu des informations comme celle-ci:

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

    /***/
})

Il s'est avéré que j'avais besoin d'anciens scripts du fichier de construction dll précédent (pour une vitesse de construction plus rapide), de sorte que mon fichier de module mis à jour ne fonctionne pas comme prévu. Enfin, j'ai reconstruit mon fichier dll et résolu mon problème.

Réf: Utilisation require.resolvepour obtenir le chemin du fichier résolu (nœud)


2

J'espère avoir bien compris vos besoins: obtenir le fichier de point d'entrée de certains modules. Disons que vous souhaitez obtenir le point d'entrée du jugglingdbmodule:

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

Comme vous pouvez le voir, ce n'est pas une manière "officielle" d'obtenir ce genre d'informations sur le module, donc le comportement de cette fonction peut changer d'une version à l'autre. Je l'ai trouvé dans la source du nœud: https://github.com/joyent/node/blob/master/lib/module.js#L280


2

Selon la solution @anatoliy, sur MacOS XI ont trouvé les chemins de recherche faisant

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

donc j'obtiens les chemins de recherche résolus

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

tandis que le

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

ne résoudra pas le module que je cherchais de toute façon, en fait le plus fou est que le _loadne résoudra pas le module:

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

tandis que le requiretestament:

> require('myModule')

mais je n'ai pas ce module dans

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/

alors où est ce module ???

J'ai d'abord dû faire un $ sudo /usr/libexec/locate.updatedb Puis après un café, j'ai fait locate myModuleou mieuxlocate myModule/someFile.js

et voilà, il ressort que c'était dans un dossier parent de mon projet c'est à dire en dehors du dossier racine de mon projet:

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

donc vous ne pouvez pas éviter rm -rf ../../node_modules/myModule/et un frais npm install.

Je peux affirmer que personne n'a demandé npmde scanner mon ordinateur à la recherche de modules ailleurs que dans le dossier racine de mon projet où il était censé s'exécuter ou dans le chemin de recherche des modules par défaut.


1

C'est peut-être ce que vous cherchez, vérifiez:

require.main.filename


1

La réponse de Jason était la meilleure, jusqu'à ce que Node.js ESM et le exportsdomaine sortent.

Maintenant que Node prend en charge les packages avec un exportschamp qui, par défaut, empêchera les fichiers comme package.jsonde pouvoir être résolus à moins que l'auteur du package ne décide explicitement de les exposer, l'astuce de la réponse de Jason échouera pour les packages qui ne sont pas explicitement exposés package.json.

Il existe un package appelé resolve-package-pathqui fait l'affaire.

Voici comment l'utiliser:

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

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

qui produira quelque chose comme

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

quel que soit le contenu du exportschamp du package .


Je soupçonne qu'une fois qu'un auteur exporte consciemment une partie du contenu du module, vous êtes sur un terrain encore plus instable, car maintenant l'auteur a formellement défini son interface publique. Cela aurait, je pense, tendance à entraîner une refactorisation plus agressive de choses qui ne sont pas explicitement exportées, n'est-ce pas?
Jason

@Jason C'est vrai pour les fichiers source, mais les fichiers package.json ne disparaissent pas. Je ne vois aucune raison pour laquelle ils devraient être masqués à l'importation.
trusktr
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.