Rumah  >  Artikel  >  hujung hadapan web  >  Artikel untuk bercakap tentang analisis laluan modul dalam Node.js

Artikel untuk bercakap tentang analisis laluan modul dalam Node.js

青灯夜游
青灯夜游ke hadapan
2021-12-16 19:19:312000semak imbas

Artikel ini akan membawa anda melalui analisis laluan modul dalam Node.js dan memperkenalkan kaedah analisis laluan modul Node Saya harap ia akan membantu semua orang.

Artikel untuk bercakap tentang analisis laluan modul dalam Node.js

requireKes

  • Pada masa ini terdapat projek
  • Laluan projek semasa/Users/rainbow/Documents/前端/脚手架开发/rainbow-test
  • Terdapat sekumpulan fail dalam direktori bin projek

Artikel untuk bercakap tentang analisis laluan modul dalam 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'
]
*/

memerlukan penghuraian dan mencari proses fail pelaksanaan modul

1 Nodejs resolusi laluan modul projek dilaksanakan melalui require.resolve kaedah.

  • require.resolve dilaksanakan melalui kaedah Module._resolveFileName
  • Module._resolveFileNameProses teras ialah:
    • Tentukan sama ada laluan adalah modul terbina dalam
    • Tidak, kemudian gunakan kaedah Module._resolveLookupPahts untuk menjana laluan yang mungkin untuk node_modules Jika laluan masuk ialah '/test/lerna/cli.js', tambahkan node_moduels tatasusunan laluan
    • Soal laluan sebenar modul melalui
    • , Module._findPath
2 >

Cache pertanyaan (Menggabungkan permintaan dan laluan melalui Module._findPath untuk menjana

)
  • merentasi tatasusunan laluan yang dijana oleh kaedah x00 dan menggabungkan cacheKey dan
  • untuk membentuk laluan fail basePath
  • Module._resolveLookupPahts jika Jika path wujud, panggil request untuk mendapatkan laluan sebenar fail
  • dan cache laluan sebenar fail ke basePath (kunci ialah cacheKey) (Module._pathCache ialah peta) fs.realPahtSync
  • 3 Module._pathCacheProses teras:

Cache pertanyaan (kunci cache ialah p. Itulah laluan yang dihasilkan. dalam Module._findPath) fs.realPahtSync

Lintas rentetan laluan dari kiri ke kanan , apabila membuat pertanyaan /, belah laluan untuk menentukan sama ada laluan itu adalah pautan lembut, tanya pautan sebenar dan jana laluan baharu p, dan kemudian terus melintasi Berikut ialah butiran:
  • Pangkalan sub-laluan yang dijana semasa proses traversal akan dicache dalam knownHard dan cache untuk mengelakkan pertanyaan berulang
  • Selepas traversal selesai, laluan sebenar yang sepadan dengan modul diperolehi Pada masa ini, laluan asal akan digunakan sebagai kunci dan laluan sebenar sebagai nilai, dan disimpan Ke cache
  • 4.
  • bersamaan dengan
  • Kaedah ini memperoleh semua laluan node_modules untuk membentuk tatasusunan.

5. Prinsip pelaksanaan require.resolve.paths ialah: Module._resolveLookupPaths

Jika ia require.resolve.paths (laluan akar), terus kembali

  • ; , tukar rentetan laluan Traverse dari belakang ke hadapan, apabila / disoal, pisahkan laluan, tambah node_modules pada penghujung, dan lulus dalam tatasusunan laluan, sehingga / tidak disoal, kembalikan tatasusunan laluan /['/node_modules']
  • memerlukan Kaedah menggunakan modul terbina dalam

Apabila kami menggunakan

require('yargs')memerlukan kaedah

Apa yang sebenarnya digunakan ialah kaedah

  • 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--;
  }
};
kaedah
// 参数
id = 'yargs'
this={
 paths: Module._nodeModulePaths(process.cwd())
}

Module._nodeModulePaths

Analisis algoritma teras bagi gelung: Artikel untuk bercakap tentang analisis laluan modul dalam 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;
  };

Artikel untuk bercakap tentang analisis laluan modul dalam Node.js

Kaedah

Module._load

Kod pelaksanaan teras ialah:

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

const filename = Module._resolveFilename(request, parent, isMain);

require.resolvePenyelesaian laluan modul projek adalah melaluiDicapai dengan cara ini.

Node.jsrequire.resolve dilaksanakan melalui kaedah 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;
Proses Teras

Module._resolveFileNameTentukan sama ada laluan ialah modul terbina dalam

Jika tidak, gunakan kaedah
    untuk menggabungkan laluan dengan laluan dalam persekitaran
  • Pas
  • Tanya laluan sebenar modulModule._resolveLookupPahts
  • 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'
]

Artikel untuk bercakap tentang analisis laluan modul dalam 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获取文件的真实路径

Artikel untuk bercakap tentang analisis laluan modul dalam Node.js

fs.realPahtSync

Artikel untuk bercakap tentang analisis laluan modul dalam Node.js

更多node相关知识,请访问:nodejs 教程!!

Atas ialah kandungan terperinci Artikel untuk bercakap tentang analisis laluan modul dalam Node.js. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:juejin.cn. Jika ada pelanggaran, sila hubungi admin@php.cn Padam