一、非核心模块加载路径搜索顺序分析


假设样本代码文件路径为:g:\testroom\nodepath\index.js

//返回搜索somemodule模块的路径列表
let modulePahts = require.resolve.paths('somemodule');
console.log(modulePahts);

windows下在cmd中并进入g:\testroom\nodepath\目录执行:

​# 设置 NODE_PATH 环境变量
set NODE_PATH=e:\
node index.js​

打印结果如下:

[
  'G:\\Testroom\\nodepath\\node_modules',
  'G:\\Testroom\\node_modules',
  'G:\\node_modules',
  'e:\\',
  'C:\\Users\\Administrator\\.node_modules',
  'C:\\Users\\Administrator\\.node_libraries',
  'C:\\Program Files\\nodejs\\lib\\node'
]

可以分析出:


非核心模块加载搜索路径顺序为:

./node_modules->..遍历至根目录... -> NODE_PATH目录 -> 全局目录

 
二、Nodejs模块加载的完整搜索顺序说明


2.1 缓存  
模块在第一次加载后会被缓存。 这也意味着(类似其他缓存机制)如果每次调用 require(‘foo’) 都解析到同一文件,则返回相同的对象。

2.2 核心模块
核心模块定义在 Node.js 源代码的 lib/ 目录下。

require() 总是会优先加载核心模块。 例如, require(‘http’) 始终返回内置的 HTTP 模块,即使有同名文件。

2.3 文件模块
如果按确切的文件名没有找到模块,则 Node.js 会尝试带上 .js、 .json 或 .node 拓展名再加载。

当没有以 '/'、 './' 或 '../' 开头来表示文件时,这个模块必须是一个核心模块或加载自 node_modules 目录。

2.4 目录作为模块
可以把程序和库放到一个单独的目录,然后提供一个单一的入口来指向它。 把目录递给 require() 作为一个参数,有三种方式。

第一种方式是在根目录下创建一个 package.json 文件,并指定一个 main 模块。
例子, package.json 文件类似:

{ 
    "name" : "some-library",
    "main" : "./lib/some-library.js" 
}

如果这是在 ./some-library 目录中,则 require(’./some-library’) 会试图加载 ./some-library/lib/some-library.js。

这就是 Node.js 处理 package.json 文件的方式。

如果目录里没有 package.json 文件,或者 ‘main’ 入口不存在或无法解析:
则 Node.js 将会试图加载目录下的 index.js 或 index.node 文件。
例如,如果上面的例子中没有 package.json 文件,则 require(’./some-library’) 会试图加载:

./some-library/index.js
./some-library/index.node

如果这些尝试失败,则 Node.js 将会使用默认错误报告整个模块的缺失:

Error: Cannot find module 'some-library'

2.5 node_modules 目录加载
如果传递给 require() 的模块标识符不是一个核心模块,也没有以 '/' 、 '../' 或 './' 开头,则 Node.js 会从当前模块的父目录开始,尝试从它的 ./node_modules 目录里加载模块。 Node.js 不会附加 node_modules 到一个已经以 node_modules 结尾的路径上。

如果还是没有找到,则移动到再上一层父目录,直到文件系统的根目录。

例子,如果在 ‘/home/nodetest/projects/foo.js’ 文件里调用了 require(‘bar.js’),则 Node.js 会按以下顺序查找:

/home/nodetest/projects/node_modules/bar.js
/home/nodetest/node_modules/bar.js
/home/node_modules/bar.js
/node_modules/bar.js

2.6 从全局目录加载
2.6.1 NODE_PATH环境变量检索
如果 NODE_PATH 环境变量被设为一个以冒号分割的绝对路径列表,则当在其他地方找不到模块时 Node.js 会搜索这些路径。

windows:

set NODE_PATH=c:\

UNIX/Linux

export NODE_PATH=.

虽然NODE_PATH可以指定特殊路径(例如SET NODE_PATH=C:\,这样会检索C盘),但是一般不建议使用。

2.6.2 其他全局目录
Node.js 还会搜索以下的全局目录列表:

1: $HOME/.node_modules
2: $HOME/.node_libraries
3: $PREFIX/lib/node

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐