CommonJs 仕様が提案されるまで、JavaScript にはモジュール システムがなかったため、コードの構成が難しくなり、大規模なアプリケーションの開発が困難でした。
まず、CommonJS は Node に固有のものではなく、Nodejs はこの仕様を実装するだけです。CommonJS モジュール仕様は、主にモジュール参照、モジュール定義、モジュール識別の 3 つの部分に分かれています。 。
モジュール参照
モジュール参照とは、 require
を通じて他のモジュールを導入できることを意味します。
const { add } = require('./add'); const result = add(1,2);
Module は
ファイルをモジュールとして定義し、モジュールは 2 つの変数、つまり module とexports を提供します。 module は現在のモジュール自体、exports はエクスポートされるコンテンツ、exports はモジュールの属性です。つまり、exports は module.exports です。 require を通じて他のモジュールによってインポートされたコンテンツは、module.exports のコンテンツです。
// .jsを追加 exports.add = (a, b) => { a + b を返します。 たとえば
、 require('./add')
の場合、モジュール ID は./add
になります
。
CommonJS を通じて構築されたモジュールのインポートおよびエクスポート メカニズムにより、ユーザーは変数汚染を考慮することなく、大規模なアプリケーションを簡単に構築できます。
ノードモジュールの実装
ノードは CommonJs 仕様を実装し、必要な機能をいくつか追加します。 Node は CommonJs 仕様を実装するために主に次の 3 つのことを行います。
パス解析
ファイルの配置
、コンパイル、
パス解析
の実行require() を実行すると、require で受け取ったパラメータがモジュール識別子となり、ノードはモジュール識別子を介してパス解析を実行します。パス分析の目的は、モジュール識別子を通じてこのモジュールが配置されているパスを見つけることです。まず、ノード モジュールは、コア モジュールとファイル モジュールの 2 つのカテゴリに分類されます。コアモジュールはノードに付属するモジュールで、ファイルモジュールはユーザーが作成したモジュールです。同時に、ファイルモジュールは、相対パス形式のファイルモジュール、絶対パス形式のファイルモジュール、および非パス形式(エクスプレスなど)のファイルモジュールに分割されます。
ノードはファイル モジュールを見つけると、そのモジュールをコンパイル、実行し、キャッシュします。一般原則として、モジュールのフル パスをキーとして使用し、コンパイルされたコンテンツを値として使用します。これは、モジュールの導入時には必要ありません。次に、パス分析、ファイルの場所の確認、コンパイル、およびこれらの手順の実行を実行し、コンパイルされたコンテンツをキャッシュから直接読み取ることができます。
//キャッシュモジュール図: const キャッシュモジュール = { '/Usr/file/src/add.js': 'add.jsのコンパイルされた内容', 'http': 'Node に付属する http モジュールのコンパイルされたコンテンツ', 'express': '非パスカスタムファイルモジュールexpressのコンパイル済みコンテンツ' // ...
require でインポートしたモジュールを探したい場合、モジュールを検索する順序は、まずモジュールがキャッシュにあるかどうかを確認し、キャッシュにない場合はコア モジュールを確認し、次にモジュールを探すことです
。
ファイルモジュール。このうち、パス形式のファイル モジュールは、相対パスまたは絶対パスに基づいて完全なファイル パスを取得するのが簡単です。非パス形式でカスタム ファイル モジュールを見つけるのは比較的面倒です。ノードは、node_modules フォルダーからファイルを検索します。
たとえば、現在実行しているファイルは /Usr/file/index.js です
。 * /Usr/ファイル/index.js; */ const {追加} = require('追加'); const result = add(1, 2);
このモジュールでは、add モジュールを導入しました。この add は、コア モジュールでも、パス形式のファイル モジュールでもありません。
モジュールにはパス属性があります。追加モジュールを見つけるためのパスは、この属性を入力して確認できます
。 * /Usr/ファイル/index.js; */ console.log(module.paths);
ファイルディレクトリ内のノードindex.jsを実行すると、パスの値を出力できます。パスの値は次のような配列です:
[ '/Usr/ファイル/node_modules', '/Usr/node_modules', '/node_modules', ]
つまり、Node は上記のディレクトリを順番に検索して、追加モジュールが含まれているかどうかを確認します。原理はプロトタイプ チェーンと同様です。まず、現在実行しているファイルと同じ階層のディレクトリにあるnode_modulesフォルダ内で検索を開始します。node_modulesディレクトリが見つからない場合、または存在しない場合は、上位階層まで検索を続けます。
ファイルの場所の
パス分析とファイルの場所は一緒に使用されます。ファイル識別子にはサフィックスが含まれていない場合もあり、この場合、特定のファイルを見つけるには追加の処理が必要になる場合があります。
ファイル拡張子解析
const { add } = require('./add');
たとえば、上記のコードでは、ファイル識別子に拡張子がありません。このとき、ノードは .js、.json の存在を検索します。 、.node の順にドキュメントを作成します。
ディレクトリとパッケージの解析は
、上記のコードと同じです./add
で見つかるのはファイルではなく、ディレクトリまたはパッケージである可能性があります (ディレクトリかパッケージかは、パッケージの有無で判断します)。 json ファイルを追加フォルダーに追加します)。このときのファイル配置の手順は、
package.json にメイン フィールドがない場合、index もファイルとして使用され、拡張子の分析が実行されて、対応するサフィックスを持つファイルが検索されます。 。
モジュールのコンパイル
開発中に遭遇する主なモジュールは、json モジュールと js モジュールです。
json モジュールのコンパイル
json モジュールが必要な場合、Node は実際に fs.readFilcSync を使用して対応する json ファイルを読み取り、json 文字列を取得し、JSON.parse を呼び出して解析して json オブジェクトを取得し、それを次のオブジェクトに割り当てるのに役立ちます。モジュールをエクスポートし、それを要求します。
js モジュールのコンパイル
//index.js
などの js モジュールが必要な場合
const { add } = require('./add')
// add.js exports.add = (a, b) => { a + b を返します。このとき
何
が起こったのでしょうか? 変数 module、exports、require をモジュール内で直接使用できるのはなぜでしょうか。これは、Node が js モジュールをコンパイルするときに最初と最後にモジュールの内容をラップするためです。
たとえば、add.js モジュールは、実際にコンパイルされると、次のような構造にパッケージ化されます:
(function(require, exports, module) { exports.add = (a, b) => { a + b を返します。 } module.exports を返します。 })(require, module.exports, module)
つまり、作成した js ファイルは関数にパッケージ化されます。記述したのはこの関数の内容だけであり、その後の Node のパッケージ化プロセスは隠蔽されます。この関数は、require、exports、module などの一部のパラメーターの受け渡しをサポートします。
js ファイルがコンパイルされると、ノードは対応するパラメーターをこの関数に渡して実行し、module.exports 値を require 関数に返します。
上記は、Node が CommonJs 仕様を実装するための基本的なプロセスです。