node Modules API

初回公開:2018/09/29
最終更新:未

以下のドキュメントのつたない翻訳,ところどころに蛇足を加えて。

【 目次 】

Node.jsモジュールシステムでは、各ファイルは個別のモジュールとして扱われます。
たとえば、次のようなfoo.jsという名前のファイルを考えてみましょう。

const circle = require('./circle.js');
console.log(`The area of a circle of radius 4 is ${circle.area(4)}`);

最初の行では、foo.jsと同じディレクトリにあるモジュールcircle.jsをロードします。
ここにcircle.jsの内容があります:

const { PI } = Math;

exports.area = (r) => PI * r ** 2;

exports.circumference = (r) => 2 * PI * r;

モジュールcircle.jsは、関数area()とcircumference()をエクスポートしました。
特別なexportsオブジェクトに追加のプロパティを指定することにより、関数とオブジェクトがモジュールのルートに追加されます。

モジュールがNode.jsによって関数にラップされるため(モジュールラッパーを参照)、モジュールのローカル変数はプライベートになります。
この例では、変数PIはcircle.jsに対してプライベートです。

実行結果

The area of a circle of radius 4 is 50.26548245743669

module.exportsプロパティに新しい値(関数やオブジェクトなど)を割り当てることができます。

次のbar.jsはSquareクラスをエクスポートするSquareモジュールを使用します。

const Square = require('./square.js');
const mySquare = new Square(2);
console.log('The area of mySquare is ${mySquare.area()}');

squareモジュールはsquare.jsで定義されています:

// assigning to exports will not modify module, must use module.exports
module.exports = class Square {
  constructor(width) {
    this.width = width;
  }

  area() {
    return this.width ** 2;
  }
};

モジュールシステムはrequire('module')モジュールに実装されています。

実行結果

The area of mySquare is 4

メインモジュールへのアクセス

Node.jsから直接ファイルを実行すると、require.mainがそのモジュールに設定されます。
つまり、require.main === moduleをテストしてファイルが直接実行されたかどうかを判断することができます。

ファイルfoo.jsの場合、node foo.js経由で実行される場合はtrue、require('./foo')によって実行される場合はfalseです。


この事をサンプルプログラムで確認してみる。

main

require('./my_sub1.js');

if (require.main === module) {
    console.log("メインモジュールとして実行(main)");
} else {
    console.log("サブモジュールとして実行(main)");
}

sub(my_sub1.js)

if (require.main === module) {
    console.log("メインモジュールとして実行(sub))");
} else {
    console.log("サブモジュールとして実行(sub)");
}

node my_main1.js経由で実行

実行結果

C:\nodejs_work> node my_main1.js
サブモジュールとして実行(sub)
メインモジュールとして実行(main)

xxx このコードを分析するとrequire関数にはmainプロパティ(属性)が存在してnodeシステムが自動的にメインモジュールのmoduleオブジェクトをこのmainプロパティに格納してくれる。

このmodule変数とかrequire.main変数はどこからやってくるのだろう? その答えはxxxを参照。 xxx

余談ではあるが、この関係はpythonにおける__name__変数の役割を連想させる。

追補:パッケージマネージャのヒント

Node.jsのrequire()関数のセマンティクスは、多くの合理的なディレクトリ構造をサポートするのに十分一般的になるように設計されています。

dpkg、rpm、npmなどのパッケージマネージャプログラムでは、Node.jsモジュールからネイティブパッケージを変更せずにビルドすることができます。


※セマンティクス

※rpm

※dpkg

rpmはレッドハット系Linuxディストリビューションのパッケージ管理システム,そしてdpkgはDebian系のパッケージ管理システム。


以下は、うまくいくと思われるディレクトリ構造を示しています。
/usr/lib/node/<some-package>/<some-version>にあるフォルダにパッケージの特定のバージョンの内容を保持させたいとします。

パッケージはお互いに依存することができます。
パッケージfooをインストールするために、パッケージbarの特定のバージョンをインストールする必要があるかもしれません。
barパッケージ自体に依存関係があり、場合によっては、これらが衝突したり、循環的な依存関係を形成することさえあります。

Node.jsはロードする(つまり、シンボリックリンクを解決する)モジュールの実パスを検索し、ここで説明するnode_modulesフォルダ内の依存関係を探します。
この状況は、次のアーキテクチャで解決するのが非常に簡単です。

  • /usr/lib/node/foo/1.2.3/ - fooパッケージのバージョン1.2.3の内容。
  • /usr/lib/node/bar/4.3.2/ - fooが依存するバーパッケージの内容。
  • /usr/lib/node/foo/1.2.3/node_modules/bar - /usr/lib/node/bar/4.3.2/へのシンボリックリンク。
  • /usr/lib/node/bar/4.3.2/node_modules/* - barが依存するパッケージへのシンボリックリンク。

したがって、サイクルに遭遇した場合、または依存性の競合がある場合でも、すべてのモジュールは、使用可能な依存性のバージョンを取得できます。

fooパッケージのコードがrequire('bar')すると、/usr/lib/node/foo/1.2.3/node_modules/barにシンボリックリンクされたバージョンが取得されます。
次に、バーパッケージのコードがrequire('quux')を呼び出すと、/usr/lib/node/bar/4.3.2/node_modules/quuxにシンボリックリンクされているバージョンが取得されます。

さらに、パッケージを/usr/lib/nodeに直接置くのではなく、モジュールのルックアッププロセスをさらに最適化するために、/usr/lib/node_modules/<name>/<version>にパッケージを置くことができます。
そうすれば、Node.jsは/usr/node_modulesまたは/node_modulesの欠落している依存関係を探す必要はありません。

Node.js REPLでモジュールを利用できるようにするには、/usr/lib/node_modulesフォルダも$NODE_PATH環境変数に追加すると便利です。
node_modulesフォルダを使用したモジュールルックアップはすべて相対的であり、require()の呼び出しを行うファイルの実際のパスに基づいているため、パッケージ自体はどこにでも置くことができます。

すべて一緒に...

require()が呼び出されたときにロードされる正確なファイル名を取得するには、require.resolve()関数を使用します。 上のすべてをまとめると、require.resolve()が行う擬似コードの高レベルアルゴリズムは次のようになります。

require(X) from module at path Y
1. If X is a core module,
   a. return the core module
   b. STOP
2. If X begins with '/'
   a. set Y to be the filesystem root
3. If X begins with './' or '/' or '../'
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
4. LOAD_NODE_MODULES(X, dirname(Y))
5. THROW "not found"

LOAD_AS_FILE(X)
1. If X is a file, load X as JavaScript text.  STOP
2. If X.js is a file, load X.js as JavaScript text.  STOP
3. If X.json is a file, parse X.json to a JavaScript Object.  STOP
4. If X.node is a file, load X.node as binary addon.  STOP

LOAD_INDEX(X)
1. If X/index.js is a file, load X/index.js as JavaScript text.  STOP
2. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
3. If X/index.node is a file, load X/index.node as binary addon.  STOP

LOAD_AS_DIRECTORY(X)
1. If X/package.json is a file,
   a. Parse X/package.json, and look for "main" field.
   b. let M = X + (json main field)
   c. LOAD_AS_FILE(M)
   d. LOAD_INDEX(M)
2. LOAD_INDEX(X)

LOAD_NODE_MODULES(X, START)
1. let DIRS = NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
   a. LOAD_AS_FILE(DIR/X)
   b. LOAD_AS_DIRECTORY(DIR/X)

NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let I = count of PARTS - 1
3. let DIRS = [GLOBAL_FOLDERS]
4. while I >= 0,
   a. if PARTS[I] = "node_modules" CONTINUE
   b. DIR = path join(PARTS[0 .. I] + "node_modules")
   c. DIRS = DIRS + DIR
   d. let I = I - 1
5. return DIRS

以下の記事も参考になるかな

ちなみにmodule.exportsに代入せずに宣言した変数や関数は外部から呼び出す事は出来ません。
node_modulesはマジックディレクトリです。ここに宣言されたモジュールはパスの指定を省略して検索されます。
細かいルールは下記にまとめます。
...

  • jsファイルを指定する場合は拡張子の.jsはあっても無くても良い
  • json形式のファイルをロードする事も出来、配列内にオブジェクトとして要素が格納される
  • ロードするファイルはパスで指定する方法と、パスを指定しない自動探索方式がある
    • パス指定は絶対パスでも相対パスでも可
    • 自動探索方式は下記のようなルールがある
      • カレントディレクトリのnode_modulesディレクトリから名前の合致するモジュールを探す
      • カレントディレクトリにnode_modulesが存在しなければ、親ディレクトリをたどってnode_modulesディレクトリを探し、あればそこから名前の合致するモジュールを探す
    • 環境変数NODE_PATHで指定されたディレクトリから名前の合致するモジュールを探す
    • $HOME/.node_modulesディレクトリから名前の合致するモジュールを探す
    • $HOME/.node_librariesディレクトリから名前の合致するモジュールを探す
    • /usr/local/libディレクトリから名前の合致するモジュールを探す
  • 指定モジュール名にはディレクトリを指定する事ができる
    • 指定ディレクトリのpackage.jsonのmainフィールドに記述されたモジュールをロードする
    • package.jsonが存在しなければindex.jsファイルをロードする
    • index.jsファイルが無ければindex.nodeファイルをロードする。無ければ例外発生。

キャッシング

モジュールは、ロードされた後にキャッシュされます。
つまり、require('foo')へのすべての呼び出しは、(とりわけ)同じファイルとして解決される場合、返されたオブジェクトと全く同じオブジェクトを返すことを意味します。

require('foo')の複数回の呼び出しに、モジュールコードが複数回実行されることはありません。
これは重要な特徴です。
これにより、「部分的に完了した」オブジェクトを返すことができ、サイクルを引き起こした場合でも推移的な依存関係をロードすることができます。
モジュールにコードを複数回実行させるには、関数をエクスポートし、その関数を呼び出します。

モジュールキャッシングに関する警告

モジュールは解決されたファイル名に基づいてキャッシュされます。
モジュールは呼び出し元のモジュールの場所に基づいて異なるファイル名に解決する可能性があるため(node_modulesフォルダから読み込む)、require('foo')が常に的確な同じオブジェクトを返すことは保証されません。

さらに、大文字と小文字を区別しないファイルシステムやオペレーティングシステムでは、解決された異なるファイル名が同じファイルを指すことがありますが、キャッシュはそれらを異なるモジュールとして扱い、ファイルを複数回リロードします。
たとえば、require('./foo')require('./FOO')は、./fooと./FOOが同じファイルであるかどうかにかかわらず、2つの異なるオブジェクトを返します。

コアモジュール

Node.jsにはバイナリにコンパイルされたいくつかのモジュールがあります。
これらのモジュールについては、このマニュアルの他の部分で詳しく説明しています。
コアモジュールはNode.jsのソース内で定義され、lib/フォルダーにあります。
コアモジュールは、識別子がrequire()に渡されると、常に優先的にロードされます。
たとえば、require('http')は、その名前のファイルがあっても、常に組み込みのHTTPモジュールを返します。

サイクル

循環的なrequire()呼び出しがある場合、モジュールは返されたときに実行を終了していない可能性があります。

この状況を考えてみましょう:

a.js:

console.log('a starting');
exports.done = false;
const b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');

b.js:

console.log('b starting');
exports.done = false;
const a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');

main.js:

console.log('main starting');
const a = require('./a.js');
const b = require('./b.js');
console.log('in main, a.done = %j, b.done = %j', a.done, b.done);

main.jsがa.jsをロードすると、a.jsはb.jsをロードします。
その時点で、b.jsはa.jsをロードしようとします。
無限ループを防ぐために、a.jsエクスポートオブジェクトの未完成のコピーがb.jsモジュールに返されます。 b.jsはロードを終了し、そのエクスポートオブジェクトはa.jsモジュールに提供されます。

実行結果

main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done = true, b.done = true

console.logの書式指定%jはJSON形式の文字列を出力する。


循環モジュールの依存関係をアプリケーション内で正しく動作させるには、慎重な計画が必要です。

ファイルモジュール

正確なファイル名が見つからない場合、Node.jsは拡張子が.js.json、および最後に.nodeのファイルをロードしようとします。

.jsファイルはJavaScriptテキストファイルとして解釈され、.jsonファイルはJSONテキストファイルとして解析されます。
.nodeファイルは、dlopenでロードされたコンパイルされたアドオンモジュールとして解釈されます。

'./'の接頭辞が必要なモジュールは、require()を呼び出すファイルからの相対パスです。
つまり、circle.jsはfoo.jsと同じディレクトリになければなりません。require('./circle')はそれを探します。

ファイルを示すために先頭に '/'、 './'、または '../'がなければ、モジュールはコアモジュールであるか、node_modulesフォルダからロードされている必要があります。

指定されたパスが存在しない場合、require() は、codeプロパティが 'MODULE_NOT_FOUND'に設定されたErrorをスローします。

モジュールとしてのフォルダ

プログラムとライブラリを自己完結型のディレクトリに編成し、そのライブラリに単一のエントリポイントを提供すると便利です。
require()を引数としてフォルダを渡す方法は3つあります。

最初は、フォルダのルートにpackage.jsonファイルを作成し、メインモジュールを指定します。
package.jsonファイルの例は、次のようになります。

{ "name" : "some-library",
  "main" : "./lib/some-library.js" }

これが./some-libraryのフォルダにある場合、require('./some-library')は./some-library/lib/some-library.jsをロードしようとします。
これはNode.jsがpackage.jsonファイルを認識している限り。

ディレクトリにpackage.jsonファイルがない場合、または 'main'エントリが見つからないか解決できない場合、Node.jsはそのディレクトリからindex.jsまたはindex.nodeファイルをロードしようとします。

たとえば、上の例でpackage.jsonファイルがなかった場合、require('./some-library')は次のファイルをロードしようとします:

  • ./some-library/index.js
  • ./some-library/index.node

これらの試行が失敗した場合、Node.jsはモジュール全体をデフォルトエラーで失われたものとして報告します:

Error: Cannot find module 'some-library'

node_modulesフォルダからの読み込み

require()に渡されたモジュール識別子がコアモジュールではなく、 '/'、 '../'、または './'で始まらない場合、Node.jsは現在のモジュールの親ディレクトリから開始し、/node_modulesを追加し、その場所からモジュールをロードしようとします。
Nodeは、すでにnode_modulesで終わっているパスにnode_modulesを追加しません。

そこに見つからなければ、ファイルシステムのルートに達するまで親ディレクトリに移動します。

たとえば、 '/home/ry/projects/foo.js'のファイルがrequire('bar.js')をコールしたなら、Node.jsは次の場所をこの順番で探します。

  • /home/ry/projects/node_modules/bar.js
  • /home/ry/node_modules/bar.js
  • /home/node_modules/bar.js
  • /node_modules/bar.js

これにより、プログラムが依存関係をローカライズし、衝突しないようにすることができます。
モジュール名の後ろにパスサフィックスを含めることで、モジュールとともに配布される特定のファイルまたはサブモジュールを要求することができます。
例えば、require('example-module/path/to/file')は、example-moduleがある場所を基準にpath/to/fileを解決します。
接尾辞付きのパスは、同じモジュール解決セマンティクスに従います。

グローバルフォルダからのロード

もしNODE_PATH環境変数がコロンで区切られた絶対パスのリストに設定されていて、もし他の場所にこれらが見つからない場合、Node.jsはモジュールのパスを検索します。

Windowsでは、NODE_PATHはコロンの代わりにセミコロン(;)で区切られています。

元々、NODE_PATHは、現在のモジュール解決アルゴリズムが凍結される前に、様々なパスからのモジュールのロードをサポートするためにつくられました。

NODE_PATHは引き続きサポートされていますが、Node.jsエコシステムが依存モジュールを見つけるための規約に定まっているため、これはあまり必要ありません。
NODE_PATHに依存しているデプロイメントでは、NODE_PATHを設定する必要があることに気づかないときに驚くべき動作を示すことがあります。
モジュールの依存関係が変更され、NODE_PATHが検索されるときに別のバージョン(または別のモジュール)がロードされることがあります。

さらに、Node.jsは次のGLOBAL_FOLDERSのリストを検索します:

  • 1: $HOME/.node_modules
  • 2: $HOME/.node_libraries
  • 3: $PREFIX/lib/node

$HOMEはユーザのホームディレクトリ、$PREFIXはNode.jsの設定されたnode_prefixです。

これらは主に歴史的な理由によるものです。

依存関係をローカルのnode_modulesフォルダーに配置することを強く推奨します。
これらはより速く、より確実にロードされます。

モジュールラッパー

モジュールのコードが実行される前に、Node.jsはそれを次のような関数ラッパーでラップします:

(function(exports, require, module, __filename, __dirname) {
// Module code actually lives in here
});

こうすることで、Node.jsはいくつかのことを実現します:

  • これは、グローバルオブジェクトではなくモジュールにスコープされた最上位レベルの変数(var、constまたはletで定義)を保持します。
  • モジュールに実際に固有のいくつかのglobalのようにみえる変数を提供するのに役立ちます:
    • 実装者がモジュールから値をエクスポートするために使用できるモジュールとエクスポートオブジェクト。
    • 便利な変数__filenameと__dirnameは、モジュールの絶対ファイル名とディレクトリパスを含んでいます。

モジュールスコープ

__dirname

現在のモジュールのディレクトリ名。
これは__filenameのpath.dirname()と同じです。

__filename

現在のモジュールのファイル名。
これは、現在のモジュールファイルの解決された絶対パスです。

メインプログラムの場合、これはコマンドラインで使用されるファイル名と必ずしも同じではありません。

現在のモジュールのディレクトリ名については、__dirnameを参照してください。

例:

/Users/mjrからのnode example.jsの実行

console.log(__filename);
// Prints: /Users/mjr/example.js
console.log(__dirname);
// Prints: /Users/mjr

与えられた2つのモジュール:aとb、bはaの依存関係であり、ディレクトリ構造があります:

  • /Users/mjr/app/a.js
  • /Users/mjr/app/node_modules/b/b.js

b.js内の__filenameへの参照は/Users/mjr/app/node_modules/b/b.jsを返しますが、a.js内の__filenameへの参照は/Users/mjr/app/a.jsを返します。

exports

より短い方へのmodule.exportsへの参照。
exportsを使う時とmodule.exportsを使う時の詳細については、exportsショートカットに関するセクションを参照してください。

module

カレントのモジュールへの参照は、moduleオブジェクトについてのセクションを参照してください。
特に、module.exportsは、モジュールがexportし、require()によって利用可能になるものを定義するために使用されます。

require()

モジュールを要求

require.cache

モジュールは、必要なときにこのオブジェクトにキャッシュされます。
このオブジェクトからキー値を削除することによって、次のrequireはモジュールをリロードします。
これは、再ロードによってエラーが発生するネイティブアドオンには適用されないことに注意してください。

require.extensions

require.extensionsは廃止予定なのでスキップ。

require.main

Node.jsプロセスの起動時に読み込まれるエントリスクリプトを表すModuleオブジェクト。
メインモジュールへのアクセス」を参照してください。

entry.jsスクリプトの場合:

console.log(require.main);
node entry.js

実行結果

Module {
  id: '.',
  exports: {},
  parent: null,
  filename: '/absolute/path/to/entry.js',
  loaded: false,
  children: [],
  paths:
   [ '/absolute/path/to/node_modules',
     '/absolute/path/node_modules',
     '/absolute/node_modules',
     '/node_modules' ] }

require.resolve(request[, options])

  • request <string> 解決するためのモジュールパス。
  • options <Object>
    • paths <string[]> モジュールの場所を解決するためのパス。
      もし存在するなら、常に含まれている$HOME/.node_modulesのようなGLOBAL_FOLDERSを除いて、デフォルトの検索パスの代わりにこれらのパスが使用されます。
      これらのパスのおのおのは、node_modules階層がこの場所からチェックされる事を意味するモジュール解決アルゴリズムの開始点として使用される事に注意してください。
  • Returns: <string>

モジュールの場所を調べるには、内部require()機構を使用しますが、モジュールをロードするよりむしろ、ただ解決されたファイル名を返します。

require.resolve.paths(request)

リクエストの解決中に検索されたパスを含む配列を返します。
リクエスト文字列がコアモジュール(httpやfsなど)を参照する場合はnullを返します。

`module`オブジェクト

各モジュールで、モジュール自由変数は、現在のモジュールを表すオブジェクトへの参照です。
便宜上、module.exportsは、モジュールグローバルなexports変数を介してアクセスすることもできます。
モジュールは実際にはグローバルではなく、むしろ各モジュールに対してローカルである。

module.children

これによりmoduleオブジェクトは初めて要求される。

module.exports

module.exportsオブジェクトは、Moduleシステムによって作成されます。
時にはこれは容認できません。
多くの場合、モジュールはあるクラスのインスタンスになります。
これを行うには、目的のエクスポートオブジェクトをmodule.exportsに割り当てます。
エクスポートに目的のオブジェクトを割り当てると、単にローカルエクスポート変数をリバインドするだけで済みますが、これはおそらく望ましいものではありません。

たとえば、a.jsというモジュールを作成しているとします。

const EventEmitter = require('events');

module.exports = new EventEmitter();

// Do some work, and after some time emit
// the 'ready' event from the module itself.
setTimeout(() => {
  module.exports.emit('ready');
}, 1000);

次に、別のファイルで行うことができます:

const a = require('./a');
a.on('ready', () => {
  console.log('module "a" is ready');
});

module.exportsへの代入は直ちに行わなければならないことに注意してください。
どのコールバックでも実行することはできません。
これは動作しません:

x.js:

setTimeout(() => {
  module.exports = { a: 'hello' };
}, 0);

y.js:

const x = require('./x');
console.log(x.a);

exportsショートカット

exports変数はモジュールのファイルレベルスコープ内で使用でき、モジュールが評価される前にmodule.exportsの値が割り当てられます。
それはショートカットを許可するので、module.exports.f = ...はexports.f = ...のようにより簡潔に書くことができます
ただし、変数と同様に、エクスポートに新しい値が割り当てられても、それはもはやmodule.exportsにバインドされません。

module.exports.hello = true; // Exported from require of module
exports = { hello: false };  // Not exported, only available in the module

module.exportsプロパティが新しいオブジェクトに完全に置き換えられている場合、エクスポートの再割り当ても一般的です。

module.exports = exports = function Constructor() {
  // ... etc.
};

この動作を説明するために、require()の仮想的な実装を想像してみましょう。
これはrequire()が実際に行っている処理と非常によく似ています。

function require(/* ... */) {
  const module = { exports: {} };
  ((module, exports) => {
    // Module code here. In this example, define a function.
    function someFunc() {}
    exports = someFunc;
    // At this point, exports is no longer a shortcut to module.exports, and
    // this module will still export an empty default object.
    module.exports = someFunc;
    // At this point, the module will now export someFunc, instead of the
    // default object.
  })(module, module.exports);
  return module.exports;
}

module.filename

モジュールへの完全に解決されたファイル名。

module.id

モジュールの識別子。 通常これは完全に解決されたファイル名です。

module.loaded

モジュールのロードが完了したかどうか、ロード中かどうか。

module.parent

これを最初に要求したモジュール。

module.paths

モジュールの検索パス。

module.require(id)

  • id <string>
  • Returns: <Object> 解決されたモジュールからのmodule.exports

module.requireメソッドは、元のモジュールからrequire()が呼び出されたかのように、モジュールをロードする方法を提供します。

これを行うには、モジュールオブジェクトへの参照を取得する必要があります。
require()はmodule.exportsを返しそして通常は特定のモジュールのコード内でのみ使用可能なので、明示的にエクスポートする必要があります。

`Module`オブジェクト

モジュールのインスタンス(ファイルモジュールでよく見られるモジュール変数)と対話するときに、一般的なユーティリティメソッドを提供します。 require('module')を介してアクセスします。

module.builtinModules

ノードv9.3.0以降

Node.jsによって提供されるすべてのモジュールの名前のリスト。 モジュールがサードパーティーによってメンテナンスされているかどうかを確認するために使用できます。

このコンテキストのモジュールは、モジュールラッパーによって提供されるのと同じオブジェクトではない事に注意してください。 それにアクセスするには、Moduleモジュールが必要です:

const builtin = require('module').builtinModules;

訳者による蛇足

他に参考になりそうな記事

訳者なりにまとめてみると、

各モジュールはモジュールラッパーにより、以下の変数がモジュール毎に与えられる。

exports, require, module, __filename, __dirname

exports

exports変数はmodule.exportsのショートカットでmodule.exportsのコ-ディングを簡潔にするために使う事ができる。 しかし注意しなければならないのはexports変数にはmodule.exportsへの参照が格納されており、この参照が失われるとexports変数は用をなさなくなる。

export.x=objX
module.exports.y=objX

といった使い方は良いがxとyは両方ともエクスポートされる。

exports=otherValue

module.exports=otherValue

のように、exports変数やmodule.exportsへ直接値を代入するとmodule.exportsとexportsとの関係性が失われてしまう。 この場合、exports変数へ代入された値は他のモジュールへエクスポートされなくなってしまう。

require

require関数はサブモジュールを読み込む関数であるが、requireにはrequire.mainなどの属性が定義されていてrequireに付随する情報を得る事ができる。

module

moduleオブジェクトにはmodule.exportsの他にも様々な属性が定義されている。 これらの属性をlogに出力してみると

C:\home\ichi\rd\nodejs\main.js

require('./sub/sub_module_a');
showModuleElements = require('./sub/sub_module_b').showModuleElements;

console.log("====================== mainモジュール");
console.log("__filename=", __filename);
console.log("__dirname=", __dirname);
showModuleElements(module);

C:\xxx\yyy\zzz\nodejs\sub\sub_module_a.js

showModuleElements = require('./sub_module_b').showModuleElements;

console.log("====================== subモジュールa");
console.log("__filename=", __filename);
console.log("__dirname=", __dirname);
showModuleElements(module);

C:\xxx\yyy\zzz\nodejs\sub\sub_module_b.js

function showModuleElements(someModule) {
    console.log("module.id=", someModule.id);
    console.log("module.filename=", someModule.filename);
    console.log("module.loaded=", someModule.loaded);
    console.log("module.paths=%j", someModule.paths);
    console.log("module.parent");
    showSubModuleElements(someModule.parent);
    console.log("module.children");
    someModule.children.forEach(showSubModuleElements);
}

function showSubModuleElements(someModule) {
    if (someModule == null) {
        console.log("\tnull");
    } else {
        console.log("\tmodule.id=%s, module.filename=", someModule.id, someModule.filename);
    }
}

console.log("====================== subモジュールb");
console.log("__filename=", __filename);
console.log("__dirname=", __dirname);
showModuleElements(module);

exports.showModuleElements = showModuleElements;

実行結果

====================== subモジュールb
__filename= C:\xxx\yyy\zzz\nodejs\sub\sub_module_b.js
__dirname= C:\xxx\yyy\zzz\nodejs\sub
module.id= C:\xxx\yyy\zzz\nodejs\sub\sub_module_b.js
module.filename= C:\xxx\yyy\zzz\nodejs\sub\sub_module_b.js
module.loaded= false
module.paths=["C:\\home\\ichi\\rd\\nodejs\\sub\\node_modules","C:\\home\\ichi\\rd\\nodejs\\node_modules","C:\\home\\ichi\\rd\\node_modules","C:\\home\\ichi\\node_modules","C:\\home\\node_modules","C:\\node_modules"]
module.parent
        module.id=C:\xxx\yyy\zzz\nodejs\sub\sub_module_a.js, module.filename= C:\xxx\yyy\zzz\nodejs\sub\sub_module_a.js
module.children
====================== subモジュールa
__filename= C:\xxx\yyy\zzz\nodejs\sub\sub_module_a.js
__dirname= C:\xxx\yyy\zzz\nodejs\sub
module.id= C:\xxx\yyy\zzz\nodejs\sub\sub_module_a.js
module.filename= C:\xxx\yyy\zzz\nodejs\sub\sub_module_a.js
module.loaded= false
module.paths=["C:\\home\\ichi\\rd\\nodejs\\sub\\node_modules","C:\\home\\ichi\\rd\\nodejs\\node_modules","C:\\home\\ichi\\rd\\node_modules","C:\\home\\ichi\\node_modules","C:\\home\\node_modules","C:\\node_modules"]
module.parent
        module.id=., module.filename= C:\xxx\yyy\zzz\nodejs\main.js
module.children
        module.id=C:\xxx\yyy\zzz\nodejs\sub\sub_module_b.js, module.filename= C:\xxx\yyy\zzz\nodejs\sub\sub_module_b.js
====================== mainモジュール
__filename= C:\xxx\yyy\zzz\nodejs\main.js
__dirname= C:\xxx\yyy\zzz\nodejs
module.id= .
module.filename= C:\xxx\yyy\zzz\nodejs\main.js
module.loaded= false
module.paths=["C:\\home\\ichi\\rd\\nodejs\\node_modules","C:\\home\\ichi\\rd\\node_modules","C:\\home\\ichi\\node_modules","C:\\home\\node_modules","C:\\node_modules"]
module.parent
        null
module.children
        module.id=C:\xxx\yyy\zzz\nodejs\sub\sub_module_a.js, module.filename= C:\xxx\yyy\zzz\nodejs\sub\sub_module_a.js
        module.id=C:\xxx\yyy\zzz\nodejs\sub\sub_module_b.js, module.filename= C:\xxx\yyy\zzz\nodejs\sub\sub_module_b.js
ページのトップへ戻る