Node.js v0.11.11 マニュアル & ドキュメンテーション


Modules#

Stability: 5 - Locked

Node はシンプルなモジュールローディングシステムを持ちます。 Node では、ファイルとモジュールは1対1に対応します。 例として、 foo.js は、同じディレクトリにある circle.js をロードしています。

foo.js の内容:

var circle = require('./circle.js');
console.log( 'The area of a circle of radius 4 is '
           + circle.area(4));

circle.js の内容:

var PI = Math.PI;

exports.area = function (r) {
  return PI * r * r;
};

exports.circumference = function (r) {
  return 2 * PI * r;
};

circle.js モジュールは area()circumference() を公開しています。 関数やオブジェクトをモジュールのルートに加えるには、 exports という特別なオブジェクトに加えます。

モジュールのローカル変数は関数に包まれているかのようにプライベートになります。 この例の場合、変数 PIcircle.js のプライベート変数です。

モジュールのルートとして関数 (たとえばコンストラクタ) を後悔したり、 プロパティを一つずつ代入するのではなく、完全なオブジェクトを一度に 公開したければ、exports の代わりに module.exportsに代入します。

以下では、bar.jssquare モジュールが公開するコンストラクタを 使用しています。

var square = require('./square.js');
var mySquare = square(2);
console.log('The area of my square is ' + mySquare.area());

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

// assigning to exports will not modify module, must use module.exports
module.exports = function(width) {
  return {
    area: function() {
      return width * width;
    }
  };
}

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

Cycles#

require() が循環的に呼び出される場合、実行が完了していないモジュールが 返されることがあります。

次の状況を考えてください:

a.js:

console.log('a starting');
exports.done = false;
var 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;
var 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');
var a = require('./a.js');
var b = require('./b.js');
console.log('in main, a.done=%j, b.done=%j', a.done, b.done);

main.jsa.js をロードすると、a.jsb.js をロードします。 ポイントは、b.jsa.js のロードを試みることです。 無限ループを避けるため、a.js がエクスポートしたオブジェクトの 未完了のコピーb.js モジュールに返されます。 b.js のロードが完了すると、exports オブジェクトが a.js モジュールに 提供されます。

main.js が両方のモジュールをロードするまでには、どちらも完了します。 このプログラムの出力はこのようになります:

$ node main.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

プログラムが循環参照するモジュールを持つ場合は、計画が適切か確認してください。

Core Modules#

Node にはバイナリにコンパイル済みのいくつかのモジュールがあります。 これらのモジュールについては、このドキュメントの他の場所でより詳しく記述されています。

コアモジュールは、 Node のソースの lib/ フォルダにて定義されています。

require() では常にコアモジュールの識別名を優先的に解釈します。 例えば require('http') は、例え同名のファイルが存在していたとしても、常にビルトイインの HTTP モジュールを返します。

File Modules#

指定された名前のファイルが見つからなければ、 Node は指定されたファイル名に .js.json、または .node を付けたものを読み込もうとします。

.js ファイルは JavaScript ファイルとして解釈され、 .json ファイルは JSON ファイルとして解釈されます。 一方 .node ファイルはコンパイル済みのアドオンモジュールとして解釈され、 dlopen を使って読み込まれます。

'/' から始まるモジュールは、ファイルへの絶対パスと見なされます。 例えば、 require('/home/marco/foo.js')/home/macro/foo.js を読み込みます。

'./' から始まるモジュールは、 require() を呼んだファイルからの相対パスになります。 すなわち、 foo.js から require('./circle') によって circle.js を読み込むには、 circle.jsfoo.js と同じディレクトリに存在していなければなりません。

'/' や './' が先頭になければ、モジュールは "コアモジュール" であるかもしくは node_modules フォルダから読み込まれることになります。

与えられたパスが存在しなかった場合、require()code プロパティに 'MODULE_NOT_FOUND' を設定したエラーをスローします。

Loading from node_modules Folders#

もし require() に渡されたモジュール識別子がネイティブモジュールではなく、かつ '/''../''./' から始まらないならば、 Node は現在のモジュールの親ディレクトリに '/node_modules' を付与してそこからモジュールを読み込もうとします。

そこに見つからない場合はさらに親ディレクトリに移動し、モジュールが見つかるか root ディレクトリに到達するまで同様のことを繰り返していきます。

例えば '/home/ry/projects/foo.js' の中で require('bar.js') を呼んでいた場合、 Node は下記の位置を上から順番に見ていきます。

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

この仕組みによって、プログラムはクラッシュを避けるために依存関係を上書きすることができるのです。

Folders as Modules#

プログラムとライブラリをディレクトリ内にまとめて、そのエントリポイントを提示するという便利な方法もあります。 それには require() に引数として何を渡すかによって3通りの方法があります。

1つ目は、 package.json というファイルをフォルダ直下に作成し、 main モジュールを指定するという方法です。 例えば、 package.json は以下のようなファイルになります:

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

もし ./some-library フォルダ内にこのファイルがあれば、 require('./some-library')./some-library/lib/some-library.js を読みにいきます。

これは、 Node が package.json の存在に気づくことによってもたらされます。

もし package.json がディレクトリに存在していなければ、 Node はそのディレクトリで index.js もしくは index.node を探します。 例えば、もし上の例で package.json がいるが存在しないとすると、 require('./some-library') は以下のファイルを読み込もうとします:

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

Caching#

モジュールは初めて読み込まれたときにキャッシュされます。 すなわち(他のキャッシュと同様に) require('foo') を呼ぶたびに、もし引数の意味するものが同一のファイルであったなら全く同一のオブジェクトが返されます。

require('foo') が複数回呼び出されても、モジュールが複数回実行されることにはなりません。 これは重要な特徴です。 そのため、「部分的に完了した」オブジェクトを返すことで、 推移的な依存関係が循環していてもロードすることができます。

もしモジュールを複数回実行したければ、関数を公開して、 その関数を呼び出してください。

Module Caching Caveats#

モジュールは解決されたファイル名に基づいてキャッシュされます。 異なる場所にあるモジュールから呼び出されたモジュールは、 (node_module フォルダからロードされるため) 異なったファイル名で 解決されることがあるため、 require('foo') が常に同じオブジェクトを返す 保証はなく、異なるファイルとして解決されます。

The module Object#

!-- name=module -->

  • {Object}

どのモジュールでも、module 自由変数は現在のモジュールを表現するオブジェクトを 参照します。 利便性のため、module.exportsexports オブジェクトを通じて 参照することもできます。 module は実際はグローバルではなく、各モジュールのローカル変数です。

module.exports#

  • Object

module.exports オブジェクトはモジュールシステムによって作成されます。 時々これは受け入れらません; 多くの人々は、モジュールが何らかのクラスのインスタンスであることを望みます。 それには、公開したいオブジェクトを module.exports に割り当てます。 望ましいオブジェクトを exports へ代入することは、ローカル変数 exports への 再代入に過ぎずないことに注意すべきです。 それはおそらく、やりたかったことではないでしょう。

例えば a.js と呼ばれるモジュールを作るとしたら

var EventEmitter = require('events').EventEmitter;

module.exports = new EventEmitter();

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

そして別のファイルで

var a = require('./a');
a.on('ready', function() {
  console.log('module a is ready');
});

module.exports への代入はすぐに行わなければなりません。 コールバックの中ではできません。以下は動きません。

x.js:

setTimeout(function() {
  module.exports = { a: "hello" };
}, 0);

y.js:

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

exports alias#

モジュール内で利用出来る exports 変数は、最初は module.exports への参照です。 他の変数と同様、それに新しい値を割り当てると元の値はもはや束縛されません。

その振る舞いを示すために、この仮定の実装を想像してください。

function require(...) {
  // ...
  function (module, exports) {
    // Your module code here
    exports = some_func;        // re-assigns exports, exports is no longer
                                // a shortcut, and nothing is exported.
    module.exports = some_func; // makes your module export 0
  } (module, module.exports);
  return module;
}

ガイドラインとして、もし exportsmodule.exports の間の関係が魔法のように 見えるなら、exports を無視して module.exports だけを使うようにしてください。

module.require(id)#

  • id {String}
  • Return: {Object} 解決されたモジュールの module.exports

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

それには module オブジェクトの参照が必要なことに注意してください。 require()module.exports を返した後、一般的に module はそのモジュールのコードで のみ 利用可能です。 それが使われるようにするには、明示的にエクスポートする必要があります。

module.id#

  • String

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

module.filename#

  • String

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

module.loaded#

  • Boolean

モジュールのロードが完了したか,あるいはローディング中かを示します。

module.parent#

  • Module Object

このモジュールを要求したモジュールです。

module.children#

  • Array

このモジュールが要求したモジュールです。

All Together...#

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 './' or '/' or '../'
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
3. LOAD_NODE_MODULES(X, dirname(Y))
4. 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.node is a file, load X.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)
2. If X/index.js is a file, load X/index.js as JavaScript text.  STOP
3. If X/index.node is a file, load X/index.node as binary addon.  STOP

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 ROOT = index of first instance of "node_modules" in PARTS, or 0
3. let I = count of PARTS - 1
4. let DIRS = []
5. while I > ROOT,
   a. if PARTS[I] = "node_modules" CONTINUE
   c. DIR = path join(PARTS[0 .. I] + "node_modules")
   b. DIRS = DIRS + DIR
   c. let I = I - 1
6. return DIRS

Loading from the global folders#

NODE_PATH 環境変数に絶対パスをコロンで区切ったリストを設定すると、 node は他で見つからなかったモジュールをそれらのパスから探します。 (注意: Windows では、NODE_PATH はコロンではなくセミコロンで区切られます)

加えると、node は以下の場所から検索します。

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

$HOME はユーザのホームディレクトリ、$PREFIX は node を configure した時の node_prefix です。

これらは主に歴史的な理由によるものです。 あなたが依存するものはローカルの node_modules フォルダに置くことが 強く推奨されます。それは素早くロードされ、確実です。

Accessing the main module#

ファイルがNodeによって直接実行される場合、その modulerequire.main に設定されます。 これは、ファイルが直接実行されたかを決定できることを意味します。

require.main === module

foo.js ファイルの場合、node foo.js と実行された場合にこれは true になりますが、require('./foo') で実行された場合は false になります。

modulefilename プロパティ (通常 __filename と同じです) を提供するため、現在のアプリケーションのエントリポイントは require.main.filename をチェックすることで得ることができます。

Addenda: Package Manager Tips#

Node の require() は普通のディレクトリ構造をサポートできるよう汎用的に設計されています。 dpkgrpmnpm のようなパッケージ管理プログラムは修正なしに Node モジュールからネイティブパッケージを組み立てることができるでしょう。

推奨するディレクトリ構造は次のようになります:

例えば /usr/lib/node/<some-package>/<some-version> フォルダに、あるパッケージの特定のバージョンを保持する形式です。

パッケージは相互に依存しあうことがあります。 foo パッケージをインストールするためにはある特定のバージョンの bar パッケージをインストールする必要があります。 bar パッケージ自身も依存関係をもっているので、ときには依存関係が衝突したり循環したりすることがあります。

Node はモジュールの realpath (シンボリックリンクを解釈します)を調べ、その依存関係を上述の node_modules フォルダの仕組みで探しにいきます。 これによって次のような構造をとてもシンプルに解釈することができます。

  • /usr/lib/node/foo/1.2.3/ - foo パッケージの中身。バージョン1.2.3。
  • /usr/lib/node/bar/4.3.2/ - bar パッケージの中身。 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 からリンクされているバージョンを取得します。 そして、 bar パッケージ内で require('quux') を呼んだら、 /usr/lib/node/bar/4.3.2/node_modules/quux からリンクされているバージョンを取得します。

さらに、モジュールを探索する過程をより最適化するために、 /usr/lib/node にパッケージを置くよりも /usr/lib/node_modules/<name>/<version> に置くのをお勧めします。 そうすることで Node は見つからない依存パッケージを /usr/node_modules/node_modules に探しにいかなくてもようなります。

Node の REPL でモジュールを使えるようにするために、 /usr/lib/node_modules フォルダを $NODE_PATH 環境変数に追加するとよいでしょう。 node_modules フォルダを使ったモジュール探索は全て相対的なものであり、 require() を呼び出したファイルの絶対パスを基準としているので、パッケージ自体はどこにでも配置することができます。