Require Resolve

Node.js

Node.js 中的 require API 在加载 commonjs 模块的时候,会做两个事情:

  1. 根据 Node.js 的算法,查找到对应的模块文件;
  2. 加载查找到的模块文件并运行。

这里,如果只是想执行第一步,但并不真的运行这个被找到的模块,可以使用 Node.js 提供的 require.resolve API。具体的调用示例如下:

const modulePath = require('some-package');

console.log(modulePath);

上面代码中,modulePath 是一个完整的文件路径,指向的位置就是 some-package 这个模块的 entry 文件(定义在 package.json 的 main 中)。默认情况下,这个 require.resolve 的查找路径是和 require API 一致的:在查找的时候,会从当前文件的目录开始,逐级往上查找 node_modules 目录下是否有需要的库。

举例来说,假设有下面这样一个目录结构:

A.js
node_modules
|- some-package
   |- index.js
|- other-package
   |- index.js
utils
|- B.js
   node_modules
   |- some-package
      |- index.js

且,假设 A.js 的代码为:

require('./utils/B');

console.log('A: ', require.resolve('some-package'));
console.log('A: ', require.resolve('other-package'));

B.js 的代码为:

console.log('B: ', require.resolve('some-package'));
console.log('B: ', require.resolve('other-package'));

那么,输出的结果为:

B: utils/node_modules/some-package/index.js
B: node_modules/other-package/index.js
A: node_modules/some-package/index.js
A: node_modules/other-package/index.js

但有的时候,只是希望可以使用 Node.js 的查找算法,但是查找的目录位置,并不一定是从当前文件所在的目录开始的。这种时候,就需要用到 require.resolve 的第二个参数了:

require.resolve('some-package', {
  paths: [
    'where-to-start-searching',
    'other-possible-search-location',
  ]
});

这里,paths 是一个数组,表示所有的搜索起始位置。Node.js 会依次以这些路径为起始点,查找各个层级往上的 node_modules 目录。一旦找到需要的库,就停止查找,否则就会一直往上直到根目录。到达根目录后,当前的查找就以失败告终。如果还有其他的查找路径,就会继续上面的操作,否则程序会抛出异常。

第二个参数的一个实际应用场景如下:假设有一个 CLI 可以用于代理执行 Webpack 命令,这时候就需要首先通过 require.resolve 命令找出当前执行 CLI 命令的目录内,Webpack 库在什么位置。然后才可以用 require 命令去加载真正在项目中使用到的 Webpack 版本,而不是 CLI 内部可能依赖的一个 Webpack 版本。

更多关于 require.resolve 命令的说明,可以参考官方的文档