1、resolve-cwd
当前工作目录解析
'use strict';const resolveFrom = require('resolve-from');module.exports = moduleId => resolveFrom(process.cwd(), moduleId);module.exports.silent = moduleId => resolveFrom.silent(process.cwd(), moduleId);
2、resolve-from
'use strict';const path = require('path');const Module = require('module');const fs = require('fs');//fromDirectory:"D:\\FrameWork\\lerna", moduleId:"lerna\\cli.js",silent:trueconst resolveFrom = (fromDirectory, moduleId, silent) => {//判断路径是否是stringif (typeof fromDirectory !== 'string') {throw new TypeError(`Expected \`fromDir\` to be of type \`string\`, got \`${typeof fromDirectory}\``);}//判断模块是否是stringif (typeof moduleId !== 'string') {throw new TypeError(`Expected \`moduleId\` to be of type \`string\`, got \`${typeof moduleId}\``);}try {//用于同步计算给定路径的规范路径名//"D:\\FrameWork\\lerna"fromDirectory = fs.realpathSync(fromDirectory);} catch (error) {if (error.code === 'ENOENT') {fromDirectory = path.resolve(fromDirectory);} else if (silent) {return;} else {throw error;}}//"D:\\FrameWork\\lerna\\noop.js"const fromFile = path.join(fromDirectory, 'noop.js');//在某个模块中给出的路径都是一个模块的相对路径,//会先调用Module._resolveFilename这个方法来查找下这个文件的真实路径的全路径文件名const resolveFileName = () => Module._resolveFilename(moduleId, {id: fromFile,filename: fromFile,//Module._nodeModulePaths 解析出node_modules目录可能的路径paths: Module._nodeModulePaths(fromDirectory)});if (silent) {try {//'D:\FrameWork\lerna\core\lerna\cli.js'return resolveFileName();} catch (error) {return;}}return resolveFileName();};module.exports = (fromDirectory, moduleId) => resolveFrom(fromDirectory, moduleId);module.exports.silent = (fromDirectory, moduleId) => resolveFrom(fromDirectory, moduleId, true);
3、Module._resolveFilename
require解析并找到模块执行文件的流程-该部分需在复习
- Nodejs项目模块路径解析是通过require.resolve方式实现的。
- require.resolve就是通过Module._resolveFileName方法实现的
- Module._resolveFileName核心流程是:
- 判断该路径是否是内置模块
- 不是,则通过Module._resolveLookupPahts方法,生成node_modules可能存在的路径,如果传入的路径是’/test/lerna/cli.js’,在每一级路径下加上node_moduels的路径数组
- 通过Module._findPath查询模块的真实路径,
- Module._findPath核心流程是:
- 查询缓存(将request和paths通过\x00合并生成cacheKey)
- 遍历 Module._resolveLookupPahts方法生成的paths数组,将path与request组成文件路径basePath
- 如果basePath存在则调用fs.realPahtSync获取文件的真实路径
- 将文件真实路径缓存到Module._pathCache(key为cacheKey)(Module._pathCache就是一个map)
- fs.realPahtSync核心流程:
- 查询缓存(缓存的key为p。即Module._findPath中生成的路径)
- 从左往右遍历路径字符串,查询到/时,拆分路径,判断该路径是否为软链接,如果是软链接则查询真实链接,并生成新路径p,然后继续让后遍历,这里有一个细节:
- 遍历过程中生成的子路径base会缓存在knownHard和cache中,避免重复查询
- 遍历完成得到模块对应的真实路径,此时会将原始路径original作为key,真实路径作为value,保存到缓存中
- require.resolve.paths等价于Module._resolveLookupPaths,该方法获取所有node_modules可能存在的路径组成一个数组。
- require.resolve.paths实现原理是:
- 如果是/(根路径)直接返回[‘/node_modules’]
否则,将路径字符串从后往前遍历,查询到/时,拆分路径,在后面加上node_modules,并传入一个paths数组,直到查询不到/后返回paths数组 ```javascript // 进入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; };
```javascriptconsole.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']作者:rainbowdiary链接:https://juejin.cn/post/7040728919967793160来源:稀土掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
、
作者:rainbowdiary
学习来自:https://juejin.cn/post/7040728919967793160

