Skip to content

module 模块使用

_resolveFilename

作用:解析模块的真实路径,例如相对路径解析为绝对路径。

mermaid
flowchart TB
  a(Module._resolveFilename) --> b{是否为内置模块}
  b --> ||d(Module._resolveLookupPaths, 将paths和环境变量node_modules合并)
  b --> ||c(End)
  d --> f(Module._findPath,在paths中解析模块的真实路径)
  f --> c
flowchart TB
  a(Module._resolveFilename) --> b{是否为内置模块}
  b --> ||d(Module._resolveLookupPaths, 将paths和环境变量node_modules合并)
  b --> ||c(End)
  d --> f(Module._findPath,在paths中解析模块的真实路径)
  f --> c
js
const parent = {
  id: fromFile, // 文件路径
  filename: fromFile, // 文件路径
  paths: Module._nodeModulePaths(fromDir), // 获取所有node_modules可能的位置
};

// 第二个参数实际上是父模块对象
Module._resolveFilename(moduleId, parent);
const parent = {
  id: fromFile, // 文件路径
  filename: fromFile, // 文件路径
  paths: Module._nodeModulePaths(fromDir), // 获取所有node_modules可能的位置
};

// 第二个参数实际上是父模块对象
Module._resolveFilename(moduleId, parent);

_nodeModulePaths

作用:生成 node_modules 可能的路径,例如

js
Module._nodeModulePaths(fromDir);

// fromDir: /home/yuangong/tmp

// [ '/home/yuangong/tmp/node_modules',
// '/home/yuangong/node_modules',
// '/home/node_modules',
// '/node_modules' ]
Module._nodeModulePaths(fromDir);

// fromDir: /home/yuangong/tmp

// [ '/home/yuangong/tmp/node_modules',
// '/home/yuangong/node_modules',
// '/home/node_modules',
// '/node_modules' ]

_findPath

mermaid
flowchart TB
  a(Module._findPath) --> b{查询缓存}
  b --> ||c(直接返回结果)
  c --> d(End)
  b --> ||e(遍历paths,合并path和request)
  e --> f{文件是否存在}
  f --> ||e
  f --> ||g(调用toRealPath生成真实路径)
  g --> h{路径是否存在}
  h --> ||d
  h --> ||e
flowchart TB
  a(Module._findPath) --> b{查询缓存}
  b --> ||c(直接返回结果)
  c --> d(End)
  b --> ||e(遍历paths,合并path和request)
  e --> f{文件是否存在}
  f --> ||e
  f --> ||g(调用toRealPath生成真实路径)
  g --> h{路径是否存在}
  h --> ||d
  h --> ||e

Node 模块解析流程

  • Nodejs 项目模块路径解析是通过require.resolve方法来实现的

  • require.resolve就是通过Module.resolveFileName 方法实现的

  • require.resolve实现原理:

    • Module.resolveFileName方法核心流程有 3 点:

      • 判断是否为内置模块
      • 通过ModuleresolveLookupPaths方法生成node_modules可能存在的路径
      • 通过Module.findPath查询模块的真实路径
    • Module.findPath核心流程有 4 点:

      • 查询缓存(将request和paths通过\x00合并成 cacheKey)
      • 遍历 paths 将path与request组成文件路径basePath
      • 如果basePath存在则调用fs.realPathSync获取文件真实路径
      • 将文件真实路径缓存到Module.pathCache(key 就是前面生成的 cacheKey)。
    • fs.realPathSync核心流程有 3 点:

      • 查询缓存(缓存的 key 为 p 即Module.findPath中生成的文件路径) 更多课程街
      • 从左往右遍历路径字符串,查询到/时,拆分路径,判断该路径是否为软链接,如果是软链接则查询真实链接,并生成新路径 p 然后继续往后遍历,这里有 1 个细节需要特别注意:
        • 遍历过程中生成的子路径 base 会缓存在 knownHard 和 cache 中,避免重复查询
      • 遍历完成得到模块对应的真实路径,此时会将原始路路径 original 作为 key,真实路径作为 value,保存到缓存中
  • require.resolve.paths等价于Module.resolveLookupPaths,该方法用于获取所有node_modules

    • 如果路径为/(根目录),直接返回['/node_modules']
    • 否则,将路径字符串从后往前遍历,查询到/时,拆分路径,在后面加上node_modules,并传入一个paths数组,直至查询不到/后返回paths数组