L'enveloppement nécessite dans Node.js qui peut résoudre l'appel relatif au chemin relatif

J'essaie de créer un wrapper nécessaire pour charger des dépendances, mais j'ai trouvé une chose difficile à faire fonctionner comme l'original nécessite une fonction. Lorsque le chemin d'accès est relatif, le wrapper ne peut pas résoudre le problème car mon chargeur et les fichiers d'appel ne sont pas dans un même dossier. Voici une description simplifiée.

index.js lib/ loader.js foo/ bar.js baz.js 

Index.js

 var loader = require('./lib/loader.js'), bar = require('./foo/bar.js'); bar(loader); 

Lib / loader.js

 module.exports = function (path) { return require(path); }; 

Foo / bar.js

 module.exports = function(loader) { var baz = loader('./baz.js'); console.log(baz); }; 

Foo / baz.js

 module.exports = 'baz'; 

Évidemment, lorsque l'index.js est exécuté, le fichier baz.js ne peut pas être trouvé. Existe-t-il un moyen de résoudre le fichier correct?

J'ai trouvé une solution relative mais ça ne fonctionne pas.

Vous pouvez utiliser module.require pour appeler require dans le contexte d'un autre module, afin que vous puissiez le faire en passant ce contexte dans la méthode du loader :

Lib / loader.js

 module.exports = function (moduleContext, path) { return moduleContext.require(path); }; 

Foo / bar.js

 module.exports = function(loader) { var baz = loader(module, './baz.js'); console.log(baz); } 

En utilisant __dirname

__dirname peut être ce dont vous avez besoin ici. Vous pouvez l'utiliser pour transformer un chemin relatif en un chemin absolu qui fonctionnera avec le require .

 var resolve = require('path').resolve; var relativePathToModule = './a/b/c'; // resolve is not strictly necessary, but it does clean up the path for you. var absolutePathToModule = resolve(__dirname + relativePathToModule); 

Vous pouvez passer absolutePathToModule à un besoin dans n'importe quel module et il trouvera toujours le bon module.

Notez que __dirname est le chemin absolu du répertoire du module dans lequel il est utilisé.

Utiliser require.resolve

Alternativement, vous pouvez utiliser le mécanisme require pour résoudre le module pour vous:

 var relativePathToModule = './a/b/c'; var absolutePathToModule = require.resolve(relativePathToModule); 

Cela permet de lancer quand aucun module ne peut être résolu et en omettant le __dirname .

Remarque

Ceux-ci ne font pas tout ce que vous voulez, mais sont proches de la façon dont vous résolvez les chemins. Les deux require et __dirname appartiennent au module dans __dirname ils sont utilisés, de sorte que toute autre chose signifie passer le contexte d'un module autour d'utiliser la machine ci-dessus dans un autre module (voir la réponse de JohnnyHK).

Je suis d'accord avec @JohnnyHK que passer le contexte du module est une solution cool, mais je veux toujours garder les appels simples. Enfin, je comprends la réponse que j'ai mentionnée, et j'obtiens ce que je veux.

Loader.js

 var getCaller, path; path = require('path'); getCaller = function() { var stack, traceFn; traceFn = Error.prepareStackTrace; Error.prepareStackTrace = function(err, stack) { return stack; }; stack = (new Error()).stack; Error.prepareStackTrace = traceFn; return stack[2].getFileName(); }; module.exports = function(file) { var base; base = path.dirname(getCaller()); return require(path.resolve(base, file)); }; 

La fonction getCaller utilise la pile de trace d'erreur pour obtenir le nom de fichier de l'appelant de son appelant. Je sais que c'est une approche très délicate, et je ne la recommande pas comme une solution commune car sa compatibilité avec différentes versions de Node.js n'a pas été testée.

Remarque

Ce chargeur est utilisé pour préparer les dépendances, de sorte qu'il n'a pas besoin d'itérer les dossiers node_modules. Les deux seuls cas sont le chemin relatif et le chemin absolu, et ils peuvent tous être correctement traités par ce chargeur.