中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Node.js中的模塊路徑是怎樣的

發布時間:2021-12-17 09:41:39 來源:億速云 閱讀:138 作者:iii 欄目:web開發

這篇文章主要介紹“Node.js中的模塊路徑是怎樣的”,在日常操作中,相信很多人在Node.js中的模塊路徑是怎樣的問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Node.js中的模塊路徑是怎樣的”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

Node.js中的模塊路徑是怎樣的

require案例

  • 當前有一個項目

  • 當前項目路徑/Users/rainbow/Documents/前端/腳手架開發/rainbow-test

  • 項目bin目錄下有一堆文件

Node.js中的模塊路徑是怎樣的

  • /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.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'
]
*/

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數組,將pathrequest組成文件路徑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方法

Node.js中的模塊路徑是怎樣的

// 進入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循環的核心算法解析:

Node.js中的模塊路徑是怎樣的

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);

Node.js中的模塊路徑是怎樣的

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'
]

Node.js中的模塊路徑是怎樣的

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數組,將pathrequest組成文件路徑basePath

  • 如果basePath存在則調用fs.realPahtSync獲取文件的真實路徑

Node.js中的模塊路徑是怎樣的

fs.realPahtSync

Node.js中的模塊路徑是怎樣的

到此,關于“Node.js中的模塊路徑是怎樣的”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

辽阳县| 泽州县| 平凉市| 沙河市| 九台市| 精河县| 小金县| 彭泽县| 富锦市| 曲松县| 嘉善县| 名山县| 乌兰浩特市| 陆丰市| 库尔勒市| 奉化市| 株洲市| 玉龙| 珲春市| 瓦房店市| 高安市| 汨罗市| 思茅市| 迭部县| 大兴区| 游戏| 高邑县| 景东| 河东区| 嘉黎县| 金阳县| 安溪县| 台东县| 丹江口市| 简阳市| 肥西县| 三原县| 广水市| 油尖旺区| 铅山县| 蒲城县|