Node模块路径解析怎么实现,方法操作是什么
Admin 2022-07-29 群英技术资讯 786 次浏览
今天就跟大家聊聊有关“Node模块路径解析怎么实现,方法操作是什么”的内容,可能很多人都不太了解,为了让大家认识和更进一步的了解,小编给大家总结了以下内容,希望这篇“Node模块路径解析怎么实现,方法操作是什么”文章能对大家有帮助。
require案例/Users/rainbow/Documents/前端/脚手架开发/rainbow-test
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.cjs
console.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'
]
*/1、Nodejs项目模块路径解析是通过require.resolve方式实现的。
Module._resolveFileName方法实现的Module._resolveFileName核心流程是:
Module._resolveLookupPahts方法,生成node_modules可能存在的路径,如果传入的路径是’/test/lerna/cli.js’,在每一级路径下加上node_moduels的路径数组Module._findPath查询模块的真实路径,2、Module._findPath核心流程是:
\x00合并生成cacheKey)Module._resolveLookupPahts方法生成的paths数组,将path与request组成文件路径basePathbasePath存在则调用fs.realPahtSync获取文件的真实路径Module._pathCache(key为cacheKey)(Module._pathCache就是一个map)3、fs.realPahtSync核心流程:
4、require.resolve.paths等价于Module._resolveLookupPaths,该方法获取所有node_modules可能存在的路径组成一个数组。
5、require.resolve.paths实现原理是:
/(根路径)直接返回['/node_modules']当我们使用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方式实现的。
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方法
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核心流程
\x00合并生成cacheKey)(\x00是空格的16进制)Module._resolveLookupPahts方法生成的paths数组,将path与request组成文件路径basePathfs.realPahtSync获取文件的真实路径
fs.realPahtSync

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
vue3 沙箱主要分两种,浏览器编译版本,浏览器版本是使用with语法加上proxy代理拦截;本地预编译版本,通过在模版预编译阶段转换阶段,使用转换插件transformExpression将非白名单标识符挂在在组件代理对象下
我们在写代码的时候考虑到,代码是写给别人看的,给别人用的,而且要注意的代码的可读性,可维护性,易用性等等,因此提高代码质量是很有必要的。那么我们如何提高js代码质量呢?下面小编就给大家分享一些提高Javascript代码质量的技巧。
本篇文章给大家带来了关于javascript的相关知识,主要介绍了深入理解JavaScript内存管理和GC算法,主要讲解JavaScript的垃圾回收机制以及常用的垃圾回收算法;还讲解了V8引擎中的内存管理,希望对大家有帮助。
这篇文章主要介绍了Vue3中的Refs和Ref,文章围绕Vue3中的Refs和Ref得相关资料应用举例烦人方式展开详细内容,需要的朋友可以参考一下
这篇文章主要给大家探讨vue打包的静态文件不可以直接运行的问题,对于这个问题一些朋友不是很理解,对此本文我们就来了解看看原因及解决方法,感兴趣的朋友可以参考一下,希望大家阅读完这篇文章能有所收获,下面我们一起来学习一下吧。
成为群英会员,开启智能安全云计算之旅
立即注册关注或联系群英网络
7x24小时售前:400-678-4567
7x24小时售后:0668-2555666
24小时QQ客服
群英微信公众号
CNNIC域名投诉举报处理平台
服务电话:010-58813000
服务邮箱:service@cnnic.cn
投诉与建议:0668-2555555
Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008