千家信息网

Node.js中的模块路径是怎样的

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,这篇文章主要介绍"Node.js中的模块路径是怎样的",在日常操作中,相信很多人在Node.js中的模块路径是怎样的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Nod
千家信息网最后更新 2026年11月01日Node.js中的模块路径是怎样的

这篇文章主要介绍"Node.js中的模块路径是怎样的",在日常操作中,相信很多人在Node.js中的模块路径是怎样的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Node.js中的模块路径是怎样的"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

require案例

  • 当前有一个项目

  • 当前项目路径/Users/rainbow/Documents/前端/脚手架开发/rainbow-test

  • 项目bin目录下有一堆文件

  • /bin/index.js

console.log(require.resolve("."));// /Users/rainbow/Documents/前端/脚手架开发/rainbow-test/bin/index.js  输出bin/index.js的绝对路径console.log(require.resolve.paths("."));// [ '/Users/rainbow/Documents/前端/脚手架开发/rainbow-test/bin' ] 输出的文件可能在的路径的数组
console.log(require.resolve("yargs"));// /Users/rainbow/Documents/前端/脚手架开发/rainbow-test/node_modules/yargs/index.cjsconsole.log(require.resolve.paths("yargs"));/*[  '/Users/rainbow/Documents/前端/脚手架开发/rainbow-test/bin/node_modules',  '/Users/rainbow/Documents/前端/脚手架开发/rainbow-test/node_modules',  '/Users/rainbow/Documents/前端/脚手架开发/node_modules',  '/Users/rainbow/Documents/前端/node_modules',  '/Users/rainbow/Documents/node_modules',  '/Users/rainbow/node_modules',  '/Users/node_modules',  '/node_modules',  '/Users/rainbow/.node_modules',  '/Users/rainbow/.node_libraries',  '/usr/local/Cellar/node/14.3.0_1/lib/node']*/

require解析并找到模块执行文件的流程

1、Nodejs项目模块路径解析是通过require.resolve方式实现的。

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

  • Module._resolveFileName核心流程是:

    • 判断该路径是否是内置模块

    • 不是,则通过Module._resolveLookupPahts方法,生成node_modules可能存在的路径,如果传入的路径是'/test/lerna/cli.js',在每一级路径下加上node_moduels的路径数组

    • 通过Module._findPath查询模块的真实路径,

2、Module._findPath核心流程是:

  • 查询缓存(将request和paths通过\x00合并生成cacheKey)

  • 遍历 Module._resolveLookupPahts方法生成的paths数组,将path与request组成文件路径basePath

  • 如果basePath存在则调用fs.realPahtSync获取文件的真实路径

  • 将文件真实路径缓存到Module._pathCache(key为cacheKey)(Module._pathCache就是一个map)

3、fs.realPahtSync核心流程:

  • 查询缓存(缓存的key为p。即Module._findPath中生成的路径)

  • 从左往右遍历路径字符串,查询到/时,拆分路径,判断该路径是否为软链接,如果是软链接则查询真实链接,并生成新路径p,然后继续让后遍历,这里有一个细节:

  • 遍历过程中生成的子路径base会缓存在knownHard和cache中,避免重复查询

  • 遍历完成得到模块对应的真实路径,此时会将原始路径original作为key,真实路径作为value,保存到缓存中

4、require.resolve.paths等价于Module._resolveLookupPaths,该方法获取所有node_modules可能存在的路径组成一个数组。

5、require.resolve.paths实现原理是:

  • 如果是/(根路径)直接返回['/node_modules']

  • 否则,将路径字符串从后往前遍历,查询到/时,拆分路径,在后面加上node_modules,并传入一个paths数组,直到查询不到/后返回paths数组

require使用到内置模块的方法

当我们使用require('yargs')时

require方法

  • 实际使用的是Module._load方法

Module.prototype.require = function(id) { //id = 'yargs'  validateString(id, 'id');  if (id === '') {    throw new ERR_INVALID_ARG_VALUE('id', id, 'must be a non-empty string');  }  requireDepth++;  try {    return Module._load(id, this, /* isMain */ false);  } finally {    requireDepth--;  }};
// 参数id = 'yargs'this={ paths: Module._nodeModulePaths(process.cwd())}

Module._nodeModulePaths方法

// 进入mac电脑所在的逻辑:// from => /Users/rainbow/Documents/前端/脚手架开发/lerna源码/lernas  //'from' is the __dirname of the module.  Module._nodeModulePaths = function(from) {    from = path.resolve(from);    // Return early not only to avoid unnecessary work, but to *avoid* returning    // an array of two items for a root: [ '//node_modules', '/node_modules' ]    if (from === '/')      return ['/node_modules'];    const paths = [];       // 关键算法代码    for (let i = from.length - 1, p = 0, last = from.length; i >= 0; --i) {      const code = from.charCodeAt(i);      if (code === CHAR_FORWARD_SLASH) {        if (p !== nmLen)          paths.push(from.slice(0, last) + '/node_modules');        last = i;        p = 0;      } else if (p !== -1) {        if (nmChars[p] === code) {          ++p;        } else {          p = -1;        }      }    }    // Append /node_modules to handle root paths.    paths.push('/node_modules');    return paths;  };

for循环的核心算法解析:

Module._load方法

Module._load(id, this, /* isMain */ false)

核心实现代码是:const filename = Module._resolveFilename(request, parent, isMain);

require.resolve

Node.js项目模块路径解析是通过require.resolve方式实现的。

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

// node.js内置模块require的源代码function resolve(request, options) {  validateString(request, 'request');  return Module._resolveFilename(request, mod, false, options); //核心实现}require.resolve = resolve;function paths(request) {  validateString(request, 'request');  return Module._resolveLookupPaths(request, mod); //核心代码}resolve.paths = paths;

Module._resolveFileName核心流程

  • 判断该路径是否是内置模块

  • 不是,则通过Module._resolveLookupPahts方法,将paths和环境中的路径结合起来

  • 通过Module._findPath查询模块的真实路径

return Module._resolveFilename(request, parent, isMain);

Module._resolveFilename = function(request, parent, isMain, options) {  if (NativeModule.canBeRequiredByUsers(request)) { //是否为内置模块    return request;  }  let paths;  // 让paths和环境变量中的paths结合  paths = Module._resolveLookupPaths(request, parent); //核心代码    if (parent && parent.filename) {    // 读取filename对应的package.json文件,看是否有exports字段,当前filename = false    const filename = trySelf(parent.filename, request);    if (filename) { //false      const cacheKey = request + '\x00' +          (paths.length === 1 ? paths[0] : paths.join('\x00'));      Module._pathCache[cacheKey] = filename;      return filename;    }  } //关键代码,找到本地执行文件 // Look up the filename first, since that's the cache key.   const filename = Module._findPath(request, paths, isMain, false);  if (filename) return filename;  // ...};

Module._resolveLookupPahts方法

  • 生成要查找模块的所有路径上可能存在node_modules的路径数组

  • require.resolve.paths("yargs")核心实现方法

生成

[  '/Users/rainbow/Documents/前端/脚手架开发/rainbow-test/bin/node_modules',  '/Users/rainbow/Documents/前端/脚手架开发/rainbow-test/node_modules',  '/Users/rainbow/Documents/前端/脚手架开发/node_modules',  '/Users/rainbow/Documents/前端/node_modules',  '/Users/rainbow/Documents/node_modules',  '/Users/rainbow/node_modules',  '/Users/node_modules',  '/node_modules',  '/Users/rainbow/.node_modules',  '/Users/rainbow/.node_libraries',  '/usr/local/Cellar/node/14.3.0_1/lib/node']

Module._resolveLookupPaths = function(request, parent) {  if (NativeModule.canBeRequiredByUsers(request)) {    debug('looking for %j in []', request);    return null;  }  // Check for node modules paths.  if (request.charAt(0) !== '.' ||      (request.length > 1 &&      request.charAt(1) !== '.' &&      request.charAt(1) !== '/' &&      (!isWindows || request.charAt(1) !== '\'))){     let paths = modulePaths;     if (parent != null && parent.paths && parent.paths.length) {      paths = parent.paths.concat(paths);    }    debug('looking for %j in %j', request, paths);    return paths.length > 0 ? paths : null;  }    // In REPL, parent.filename is null.  if (!parent || !parent.id || !parent.filename) {    // Make require('./path/to/foo') work - normally the path is taken    // from realpath(__filename) but in REPL there is no filename    const mainPaths = ['.'];    debug('looking for %j in %j', request, mainPaths);    return mainPaths;  }  debug('RELATIVE: requested: %s from parent.id %s', request, parent.id);  const parentDir = [path.dirname(parent.filename)];  debug('looking for %j', parentDir);  return parentDir;};

Module._findPath核心流程

  • 查询缓存(将request和paths通过\x00合并生成cacheKey)(\x00是空格的16进制)

  • 遍历Module._resolveLookupPahts方法生成的paths数组,将path与request组成文件路径basePath

  • 如果basePath存在则调用fs.realPahtSync获取文件的真实路径

fs.realPahtSync

到此,关于"Node.js中的模块路径是怎样的"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

路径 模块 方法 前端 核心 脚手架 开发 文件 查询 数组 生成 缓存 流程 代码 项目 学习 就是 链接 关键 字符 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技工作委员会毛军 美国互联网保险保险科技 科技互联网公司装修 礼当家互联网科技 小马过河互联网科技 广州凡科互联网科技 碳银互联网科技有限公司 科技类的互联网平台 互联网公司会议桌创意科技软装饰 深圳国际航运科技和互联网 广州市恰铎互联网科技有限公司 爱医互联网络科技 保险科技服务互联网营销体系 华中科技大学互联网的牛人 互联网企业科技类企业如何做账 江苏互联网科技小贷 2021世界互联网领先科技成果发布 世界互联网科技成果奖 云南互联网科技学费 科技互联网专业工作会议发言稿 中关村互联网科技集团 深圳科技互联网 互联网 科技创新 成都铂石互联网科技做什么的 河南猎农互联网科技有限公司 移动互联网年度科技创新 天津腾达互联网科技有限公司 深圳无忧互联网科技 中天科技中国工业互联网 科技互联网企业在行动
0