1、resolve-cwd

当前工作目录解析

  1. 'use strict';
  2. const resolveFrom = require('resolve-from');
  3. module.exports = moduleId => resolveFrom(process.cwd(), moduleId);
  4. module.exports.silent = moduleId => resolveFrom.silent(process.cwd(), moduleId);

2、resolve-from

  1. 'use strict';
  2. const path = require('path');
  3. const Module = require('module');
  4. const fs = require('fs');
  5. //fromDirectory:"D:\\FrameWork\\lerna", moduleId:"lerna\\cli.js",silent:true
  6. const resolveFrom = (fromDirectory, moduleId, silent) => {
  7. //判断路径是否是string
  8. if (typeof fromDirectory !== 'string') {
  9. throw new TypeError(`Expected \`fromDir\` to be of type \`string\`, got \`${typeof fromDirectory}\``);
  10. }
  11. //判断模块是否是string
  12. if (typeof moduleId !== 'string') {
  13. throw new TypeError(`Expected \`moduleId\` to be of type \`string\`, got \`${typeof moduleId}\``);
  14. }
  15. try {
  16. //用于同步计算给定路径的规范路径名
  17. //"D:\\FrameWork\\lerna"
  18. fromDirectory = fs.realpathSync(fromDirectory);
  19. } catch (error) {
  20. if (error.code === 'ENOENT') {
  21. fromDirectory = path.resolve(fromDirectory);
  22. } else if (silent) {
  23. return;
  24. } else {
  25. throw error;
  26. }
  27. }
  28. //"D:\\FrameWork\\lerna\\noop.js"
  29. const fromFile = path.join(fromDirectory, 'noop.js');
  30. //在某个模块中给出的路径都是一个模块的相对路径,
  31. //会先调用Module._resolveFilename这个方法来查找下这个文件的真实路径的全路径文件名
  32. const resolveFileName = () => Module._resolveFilename(moduleId, {
  33. id: fromFile,
  34. filename: fromFile,
  35. //Module._nodeModulePaths 解析出node_modules目录可能的路径
  36. paths: Module._nodeModulePaths(fromDirectory)
  37. });
  38. if (silent) {
  39. try {
  40. //'D:\FrameWork\lerna\core\lerna\cli.js'
  41. return resolveFileName();
  42. } catch (error) {
  43. return;
  44. }
  45. }
  46. return resolveFileName();
  47. };
  48. module.exports = (fromDirectory, moduleId) => resolveFrom(fromDirectory, moduleId);
  49. module.exports.silent = (fromDirectory, moduleId) => resolveFrom(fromDirectory, moduleId, true);

3、Module._resolveFilename

image.png
4.14-4.16没认真看 后续再复习

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,保存到缓存中
  1. require.resolve.paths等价于Module._resolveLookupPaths,该方法获取所有node_modules可能存在的路径组成一个数组。
  2. 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 === ‘/‘)

    1. return ['/node_modules'];

    const paths = [];

    // 关键算法代码 for (let i = from.length - 1, p = 0, last = from.length; i >= 0; —i) {

    1. const code = from.charCodeAt(i);
    2. if (code === CHAR_FORWARD_SLASH) {
    3. if (p !== nmLen)
    4. paths.push(from.slice(0, last) + '/node_modules');
    5. last = i;
    6. p = 0;
    7. } else if (p !== -1) {
    8. if (nmChars[p] === code) {
    9. ++p;
    10. } else {
    11. p = -1;
    12. }
    13. }

    }

    // Append /node_modules to handle root paths. paths.push(‘/node_modules’);

    return paths; };

  1. ```javascript
  2. console.log(require.resolve("yargs"));
  3. // /Users/rainbow/Documents/前端/脚手架开发/rainbow-test/node_modules/yargs/index.cjs
  4. console.log(require.resolve.paths("yargs"));
  5. /*
  6. [
  7. '/Users/rainbow/Documents/前端/脚手架开发/rainbow-test/bin/node_modules',
  8. '/Users/rainbow/Documents/前端/脚手架开发/rainbow-test/node_modules',
  9. '/Users/rainbow/Documents/前端/脚手架开发/node_modules',
  10. '/Users/rainbow/Documents/前端/node_modules',
  11. '/Users/rainbow/Documents/node_modules',
  12. '/Users/rainbow/node_modules',
  13. '/Users/node_modules',
  14. '/node_modules',
  15. '/Users/rainbow/.node_modules',
  16. '/Users/rainbow/.node_libraries',
  17. '/usr/local/Cellar/node/14.3.0_1/lib/node'
  18. ]
  19. 作者:rainbowdiary
  20. 链接:https://juejin.cn/post/7040728919967793160
  21. 来源:稀土掘金
  22. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


作者:rainbowdiary
学习来自:https://juejin.cn/post/7040728919967793160