Node.js でのモジュール パス分析について説明する記事

青灯夜游
リリース: 2021-12-16 19:19:31
転載
1915 人が閲覧しました

この記事では、Node.js でのモジュール パス分析について説明し、Nodeモジュール パス分析方法を紹介します。

Node.js でのモジュール パス分析について説明する記事

##requireCase

    現在プロジェクトがあります
  • 現在のプロジェクトパス
  • /Users/rainbow/Documents/front-end/scaffoldeddevelopment/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を通じて実装されます。コア プロセスは次のとおりです。
      パスが組み込みモジュールであるかどうかを判断します。
    • そうでない場合は、受信パスが '/test/lerna の場合、
    • Module._resolveLookupPahtsメソッドを使用して、node_modules の可能なパスを生成します。 /cli.js'、各レベルのパスの下にnode_moduelsのパス配列を追加します
    • Module._findPath# を通じてモジュールの実際のパスをクエリします
  • ##2,
Module._findPath

コア プロセスは次のとおりです:

クエリ キャッシュ (リクエストと
    \ を介したパスをマージすることによって生成されます) x00
  • cacheKey)
  • Module._resolveLookupPahts
  • メソッドによって生成されたパス配列を走査し、pathrequest を結合します。ファイル パスを形成します。basePath
  • basePath
  • が存在する場合は、fs.realPahtSyncを呼び出して、ファイルCache の実際のパスを取得します。
  • Module._pathCache# へのファイルの実際のパス ## (キーはcacheKey) (Module._pathCacheはマップ)
  • 3.
  • fs.realPahtSync
Coreプロセス:

クエリ キャッシュ (キャッシュされたキーは p です。つまり、Module._findPath で生成されたパス)

    パス文字列を左から右にトラバースし、クエリ /、分割します。パスを調べ、そのパスがソフト リンクであるかどうかを判断します。ソフト リンクの場合、リンクは実際のリンクを照会し、新しいパス p を生成し、トラバースを続けます。詳細は次のとおりです:
  • 走査プロセス中に生成されたサブパス ベースは、クエリの繰り返しを避けるために knownHard とキャッシュにキャッシュされます
  • 走査が完了すると、モジュールに対応する実際のパスが取得されます。このとき、元のパスはがキーとして使用され、実際のパスが値として使用され、キャッシュに保存されます。
  • 4,
  • require.resolve.paths
は次と同等です。

Module._resolveLookupPaths. このメソッドは、node_modules の可能なすべてのパスを取得して配列を形成します。5,require.resolve.paths

実装原則は次のとおりです:

/
    (ルート パス) の場合、# を返します。 ## 直接 ['/node_modules']
  • それ以外の場合は、パス文字列を後ろから前にたどります。/ がクエリされると、パスを分割し、最後に node_modules を追加し、パス配列に渡します。クエリ後にパス配列が見つからない/返されないまで
  • require は組み込みモジュールのメソッドを使用します

使用するときはrequire( 'yargs')

メソッドが必要な場合

実際にはModule._load

method# を使用します
    # #
    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._nodeModulePathsMethod

#

// 进入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._loadNode.js でのモジュール パス分析について説明する記事Method

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メソッドを使用しますパスを結合し、環境内のパスを結合します。

モジュールの実際のパスをクエリします。
    Module._findPath
  • return Module._resolveFilename(request 、親、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' ]
    ログイン後にコピー

    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相关知识,请访问:nodejs 教程!!

以上がNode.js でのモジュール パス分析について説明する記事の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:juejin.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!