require
require 支持加载资源的类型
require 支持加载的资源类型有: .js/.json/.node
and 其他任何类型的文件
如果加载的是 .js
文件类型的话, require 要求必须输出 module.exports/exports.
输出模块
如果加载的是.json
文件,require 会对文件通过 JSON.parse
进行解析并输出对象
.node
类型文件是一个 C++ 的插件,require 通过 process.dlopen
来打开这个 C++插件
如果加载的是其他类型的文件,require 会默认通过 .js 引擎进行解析
node.js 模块路径解析流程
- node.js 项目模块路径解析是通过
require.resolve
方法实现的 require.resolve
就是通过Module._resolveFileName
方法实现的require.resolve
实现原理:Module._resolveFileName
方法核心流程有 3 点:- 在执行过程中判断模块是否为内置模块,如果是内置模块,直接返回
- 如果不是内置模块,通过
Module._resolveFileName
方法生成所有node_modules
可能存在的路径 - 然后通过
Module._findPath
查询模块的真实路径
Module._findPath
核心流程有四点:- 查询缓存(将 request 和 paths 通过空格
\x00
合并组合成 cacheKey),如果在缓存中查找到,则直接返回 - 如果没有在缓存中找到,则遍历所有
node_modules
可能存在的路径paths
, 将每一个路径 path 与 模块名称 request 组成生成文件路径 basePath - 判断 basePath 是否存在,如果 basePath 存在,则调用
fs.realPathSync
获取文件真实路径,如果不存在,则继续遍历下一个 path,直到 path 遍历完 - 如果找到了文件的真实路径,就会直接返回,并且将文件真实路径缓存到
Module._pathCache
中(用到的 key 就是前面生成的 cacheKey)
- 查询缓存(将 request 和 paths 通过空格
fs.realPathSync
核心流程有 3 点:- 查询缓存(缓存的 key 为 p 就是 path,就是在
Module._findPath
中生成的文件路径 basePath) - 如果在缓存中没有查到,就会将缓存的 key(路径字符串 basePath)从左往右遍历,查询到
/
时,拆分路径,把前面的路径拿出来,判断该路径是否为软链接,如果是软链接则调用操作系统的一个 API 查询它的真实路径,并生成新路径 p,然后继续往后遍历,只有有一个细节需要特别注意:- 遍历过程中生成的子路径 base 会缓存在 knownHard(是当前查找过的&缓存中没有的路径) 和 cache 中,避免重复查询
- 遍历完成后得到模块对应的真实路径,此时会将原始路径 original 作为 key,真实路径作为 value,保存到缓存中
- 查询缓存(缓存的 key 为 p 就是 path,就是在
require.resolve.paths
等价于Module._resolveLookupPaths
,该方法用于获取所有 node_modules 可能存在的路径require.resolve.paths
实现原理:- 如果路径为
/
(根目录),直接返回['/node_modules']
- 否则,将路径字符串从后往前遍历,查询到
/
时,拆分路径,在后面加上 node_modules,并传入一个 paths 数组,直至查询不到/
后返回 paths 数组
- 如果路径为