简体   繁体   English

在Node.js中包裹需要可以解析相对路径调用

[英]Wrap require in Node.js which can resolve relative path call

I'm trying to create a require wrapper to load dependencies, but I found one thing difficult to make it works as the original require function. 我正在尝试创建一个require包装器来加载依赖项,但我发现有一件事很难让它作为原始的require函数工作。 When the path is a relative one, the wrapper cannot resolve to the correct one since my loader and the caller files are not in a same folder. 当路径是相对路径时,包装器无法解析为正确的路径,因为我的加载器和调用者文件不在同一个文件夹中。 Here is a simplified description. 这是一个简化的描述。

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

index.js index.js

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

lib/loader.js LIB / loader.js

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

foo/bar.js 富/ bar.js

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

foo/baz.js 富/ baz.js

module.exports = 'baz';

Obviously, when the index.js is executed, baz.js file cannot be found. 显然,当执行index.js时,找不到baz.js文件。 Is there any way to resolve to the correct file? 有没有办法解决到正确的文件?

I've found a relative solution but it's not working. 我找到了一个相对的解决方案,但它没有用。

You can use module.require to call require from another module's context, so you could do this by passing that context into the loader method: 您可以使用module.require从另一个模块的上下文中调用require ,因此您可以通过将该上下文传递给loader方法来完成此操作:

lib/loader.js LIB / loader.js

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

foo/bar.js 富/ bar.js

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

I agree with @JohnnyHK that passing the module context is a cool solution, but I still want to keep the calls simple. 我同意@JohnnyHK传递module上下文是一个很酷的解决方案,但我仍然希望保持调用简单。 Finally I understand the answer I mentioned, and I get what I want. 最后,我理解我提到的答案 ,我得到了我想要的东西。

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

The getCaller function use error trace stack to get the filename of the caller of it's caller. getCaller函数使用错误跟踪堆栈来获取其调用者的调用者的文件名。 I know it's a very tricky approach, and I don't recommend it as a common solution since its compatibility to different versions of Node.js has not been tested. 我知道这是一个非常棘手的方法,我不推荐它作为一种常见的解决方案,因为它与不同版本的Node.js的兼容性尚未经过测试。

Note 注意

This loader is used for preparing dependencies, so it doesn't need to iterate node_modules folders. 此加载器用于准备依赖项,因此它不需要迭代node_modules文件夹。 The only two cases are relative path and absolute path, and they can all be correctly processed by this loader. 只有两种情况是相对路径和绝对路径,它们都可以被这个加载器正确处理。

Using __dirname 使用__dirname

__dirname may be what you need here. __dirname可能就是你需要的。 You can use it to turn a relative path into an absolute path which will work with require . 您可以使用它将相对路径转换为绝对路径,该路径将与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);

You can pass absolutePathToModule to a require in any module and it will always find the right module. 您可以在任何模块中将absolutePathToModule传递给require,它将始终找到正确的模块。

Note that __dirname is the absolute path to the directory of the module in which it is used. 请注意, __dirname是使用它的模块的目录的绝对路径。

Using require.resolve 使用require.resolve

Alternatively, you can use the require machinery itself to resolve the module for you: 或者,您可以使用require机器本身为您解析模块:

var relativePathToModule = './a/b/c';

var absolutePathToModule = require.resolve(relativePathToModule);

This has the benefit of throwing when no module can be resolved, and omitting the __dirname . 这样可以在没有模块可以解析时抛出,并省略__dirname

Note 注意

These don't quite do what you want, but are close to the way require resolves paths. 这些并不是你想要的,但是接近require解析路径的方式。 Both require and __dirname belong to the module they are used in, so anything else will mean passing the context of a module around to use the above machinery in another module (see JohnnyHK's answer). require__dirname属于它们所使用的模块,所以其他任何东西都意味着传递模块的上下文以在另一个模块中使用上述机制(参见JohnnyHK的答案)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM