ほぼすべての Node.js 開発者は、require() 関数が何をするのかを説明できますが、それがどのように機能するかを実際に知っている人はどれだけいるでしょうか?私たちはライブラリやモジュールをロードするために毎日これを使用していますが、その動作は私たちにとって謎です。
好奇心から、私はノードのコアコードを調べて、内部で何が起こっているのかを調べました。しかし、これは単一の関数ではありません。node のモジュール システムで module.js を見つけました。このファイルには、各ファイルのロード、コンパイル、キャッシュを制御する、驚くほど強力だが比較的馴染みのないコア モジュールが含まれています。 「require()」、その出現は氷山の一角にすぎません。
モジュール.js
このモジュールの 2 番目の主要なタスクは、ノードのモジュール読み込みメカニズムを処理することです。私たちが使用する独立した操作「require」関数は、実際には module.require の抽象概念であり、それ自体は Module._load 関数の単純なカプセル化にすぎません。このロード メソッドは各ファイルの実際のロードを処理し、そこから作業を開始します。
モジュール._load
モジュールがキャッシュに存在しない場合、Module._load はそのファイルの新しいベース モジュールを作成します。次に、新しいファイルの内容を module._compile に送信する前に読み取るようにモジュールに指示します。 [1]
上記のステップ #6 に気付いた場合は、module.exports がユーザーに返されていることがわかります。これが、使用するパブリック インターフェイスを定義するときに、exports と module.exports を使用する理由です。これは、次に Module._load が必要なコンテンツを返すためです。これ以上の機能がないことに驚いていますが、あれば便利です。
module._compile
・ここで本当の魔法が起こります。まず、このモジュール用に特別なスタンドアロンの require 関数が作成されます。これは私たち全員が必要とする、よく知られた機能です。関数自体は Module.require の単なるパッケージであり、あまり知られていない使いやすい補助メソッドも含まれています。
・require(): 外部モジュールをロードします
· require.resolve(): モジュール名を絶対パスに解決します
· require.main:メインモジュール
· require.cache: キャッシュされたすべてのモジュール
· ·require.extensions: 拡張子に応じた有効なファイル タイプごとに利用可能なコンパイル方法
require の準備が完了すると、ロードされたソース コード全体が、require、module、exports、およびその他すべての公開変数をパラメーターとして受け入れることができる新しい関数にカプセル化されます。これは、Node.js 環境との競合を防ぐためにモジュールをカプセル化するためだけに作成された関数です。
結論
これで、require のコード全体を理解し、それがどのように機能するかについて暫定的に理解しました。
これをすべて実行した場合は、最後のシークレットである require('module') を使用する準備ができています。そうです、モジュール システム自体はモジュール システムを通じてロードできます。インセプション。奇妙に聞こえるかもしれませんが、これにより、Node.js コアを深く掘り下げることなく、ユーザー空間がモジュール読み込みシステムと対話できるようになります。一般的なモジュールはこのように構築されます。 [2]
さらに詳しく知りたい場合は、module.js のソース コードを自分で調べてください。しばらく頭が痛くなるようなことがたくさんあります。最初の方は、「NODE_MODULE_CONTEXTS」とは何か、そしてそれが追加された理由、そしてそれを追加した人はボーナスポイントを獲得できるのか教えてください:)
[1] module._compile メソッドは、JavaScript ファイルを実行するためにのみ使用されます。 JSON ファイルは JSON.parse() で解析して返す必要があります
[2] ただし、どちらのモジュールも Module._resolveLookupPaths や Module._findPath などのプライベート モジュール メソッドに基づいて構築されています。あまり良くないと思うかもしれません...