モジュール: CommonJS モジュール
CommonJS モジュールは、Node.js 用に JavaScript コードをパッケージ化する元の方法です。Node.js は、ブラウザーや他の JavaScript ランタイムで使用される ECMAScript モジュール 標準もサポートしています。
Node.js では、各ファイルは別々のモジュールとして扱われます。たとえば、foo.js
という名前のファイルを考えてみましょう。
const circle = require('./circle.js')
console.log(`半径 4 の円の面積は ${circle.area(4)} です`)
最初の行で、foo.js
は 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
に対してプライベートです。
module.exports
プロパティには、新しい値(関数やオブジェクトなど)を割り当てることができます。
次のコードでは、bar.js
は Square
クラスをエクスポートする square
モジュールを使用しています。
const Square = require('./square.js')
const mySquare = new Square(2)
console.log(`mySquare の面積は ${mySquare.area()} です`)
square
モジュールは square.js
で定義されています。
// exports に代入しても module は変更されないため、module.exports を使用する必要がある
module.exports = class Square {
constructor(width) {
this.width = width
}
area() {
return this.width ** 2
}
}
CommonJS モジュールシステムは、module
コアモジュール に実装されています。
有効化
Node.js には、CommonJS モジュールと ECMAScript モジュール の 2 つのモジュールシステムがあります。
デフォルトでは、Node.js は次のものを CommonJS モジュールとして扱います。
.cjs
拡張子の付いたファイル。- 最も近い親の
package.json
ファイルに、値が"commonjs"
のトップレベルフィールド"type"
が含まれている場合の.js
拡張子の付いたファイル。 - 最も近い親の
package.json
ファイルにトップレベルフィールド"type"
が含まれていない場合、または親フォルダーにpackage.json
がない場合の.js
拡張子または拡張子のないファイル。ただし、ES モジュールとして評価されない限りエラーが発生する構文がファイルに含まれている場合を除きます。パッケージの作成者は、すべてのソースが CommonJS であるパッケージであっても、"type"
フィールドを含める必要があります。パッケージのtype
を明示的に指定することで、ビルドツールやローダーがパッケージ内のファイルをどのように解釈すべきかを判断するのが容易になります。 .mjs
、.cjs
、.json
、.node
、または.js
ではない拡張子の付いたファイル(最も近い親のpackage.json
ファイルに、値が"module"
のトップレベルフィールド"type"
が含まれている場合、これらのファイルは、プログラムのコマンドラインエントリポイントとして使用された場合ではなく、require()
を介してインクルードされている場合にのみ、CommonJS モジュールとして認識されます)。
詳細については、モジュールシステムの決定 を参照してください。
require()
を呼び出すと、常に CommonJS モジュールローダーが使用されます。import()
を呼び出すと、常に ECMAScript モジュールローダーが使用されます。
メインモジュールのアクセス
Node.js から直接ファイルが実行されると、require.main
はファイルのmodule
に設定されます。つまり、require.main === module
をテストすることで、ファイルが直接実行されたかどうかを判断できます。
foo.js
というファイルの場合、node foo.js
で実行するとtrue
になり、require('./foo')
で実行するとfalse
になります。
エントリポイントが CommonJS モジュールでない場合、require.main
はundefined
になり、メインモジュールにアクセスできなくなります。
パッケージマネージャのヒント
Node.js のrequire()
関数のセマンティクスは、妥当なディレクトリ構造をサポートするのに十分な汎用性を持つように設計されました。dpkg
、rpm
、npm
などのパッケージマネージャプログラムは、変更せずに Node.js モジュールからネイティブパッケージをビルドできるようになるでしょう。
以下に、動作する可能性のある推奨ディレクトリ構造を示します。
パッケージの特定のバージョンの中身を/usr/lib/node/<some-package>/<some-version>
に配置したいとしましょう。
パッケージはお互いに依存関係を持つことができます。foo
パッケージをインストールするには、bar
パッケージの特定のバージョンをインストールする必要がある場合があります。bar
パッケージ自体にも依存関係があり、場合によっては衝突したり、循環依存関係を形成したりする可能性があります。
Node.js はロードするモジュールのrealpath
(つまり、シンボリックリンクを解決する)を調べ、その後node_modules
フォルダ内で依存関係を検索するため、この状況は次のアーキテクチャで解決できます。
/usr/lib/node/foo/1.2.3/
:foo
パッケージのバージョン 1.2.3 の内容。/usr/lib/node/bar/4.3.2/
:foo
が依存するbar
パッケージの内容。/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.js は/usr/node_modules
または/node_modules
で不足している依存関係を検索しなくなります。
Node.js REPL でモジュールを利用できるようにするには、/usr/lib/node_modules
フォルダを$NODE_PATH
環境変数に追加することも役立つ場合があります。node_modules
フォルダを使用したモジュール検索はすべて相対的で、require()
を呼び出しているファイルの実際のパスに基づいているため、パッケージ自体はどこにでも配置できます。
require()
を使用した ECMAScript モジュールの読み込み
[履歴]
バージョン | 変更点 |
---|---|
v23.5.0 | この機能はデフォルトで実験的な警告を出力しなくなりましたが、--trace-require-module を使用すると警告を出力できます。 |
v23.0.0 | この機能は、--experimental-require-module CLI フラグの対象外になりました。 |
v23.0.0 | require(esm) で 'module.exports' インターオペラビリティエクスポートをサポート |
v22.0.0, v20.17.0 | 追加: v22.0.0, v20.17.0 |
.mjs
拡張子は ECMAScript モジュール 用に予約されています。どのファイルが ECMAScript モジュールとして解析されるかについては、モジュールシステムの決定 セクションを参照してください。
require()
は、次の要件を満たす ECMAScript モジュールのみの読み込みをサポートします。
- モジュールは完全に同期している(最上位レベルの
await
を含んでいない)。 - 次のいずれかの条件を満たしている。
ES モジュールが要件を満たしている場合、require()
はそれをロードし、モジュール名前空間オブジェクトを返します。この場合、動的な import()
と似ていますが、同期的に実行され、名前空間オブジェクトを直接返します。
次の ES モジュールの場合:
// distance.mjs
export function distance(a, b) {
return (b.x - a.x) ** 2 + (b.y - a.y) ** 2
}
// point.mjs
export default class Point {
constructor(x, y) {
this.x = x
this.y = y
}
}
CommonJS モジュールは require()
を使用してそれらをロードできます。
const distance = require('./distance.mjs')
console.log(distance)
// [Module: null prototype] {
// distance: [Function: distance]
// }
const point = require('./point.mjs')
console.log(point)
// [Module: null prototype] {
// default: [class Point],
// __esModule: true,
// }
ES モジュールを CommonJS に変換する既存のツールとの相互運用性のために、実際の ES モジュールを require()
を介してロードできる場合、返される名前空間には、default
エクスポートがある場合 __esModule: true
プロパティが含まれます。これにより、ツールによって生成されたコードは実際の ES モジュール内のデフォルトエクスポートを認識できます。名前空間が既に __esModule
を定義している場合、これは追加されません。このプロパティは実験的なものであり、将来変更される可能性があります。これは、既存のエコシステムの慣例に従って、ES モジュールを CommonJS モジュールに変換するツールによってのみ使用されるべきです。CommonJS で直接作成されたコードは、それに依存することを避けるべきです。
ES モジュールに名前付きエクスポートとデフォルトエクスポートの両方がある場合、require()
によって返される結果はモジュール名前空間オブジェクトであり、import()
によって返される結果と同様に、デフォルトエクスポートを .default
プロパティに配置します。require(esm)
が直接返すものをカスタマイズするには、ES モジュールは文字列名 "module.exports"
を使用して目的の値をエクスポートできます。
// point.mjs
export default class Point {
constructor(x, y) {
this.x = x
this.y = y
}
}
// `distance` is lost to CommonJS consumers of this module, unless it's
// added to `Point` as a static property.
export function distance(a, b) {
return (b.x - a.x) ** 2 + (b.y - a.y) ** 2
}
export { Point as 'module.exports' }
const Point = require('./point.mjs')
console.log(Point) // [class Point]
// Named exports are lost when 'module.exports' is used
const { distance } = require('./point.mjs')
console.log(distance) // undefined
上記の例では、module.exports
エクスポート名を使用すると、名前付きエクスポートは CommonJS のコンシューマーに失われます。CommonJS のコンシューマーが名前付きエクスポートにアクセスし続けられるようにするには、モジュールは、デフォルトエクスポートがプロパティとして名前付きエクスポートを添付したオブジェクトであることを確認する必要があります。たとえば、上記の例では、distance
をデフォルトエクスポートである Point
クラスに静的メソッドとして添付できます。
export function distance(a, b) {
return (b.x - a.x) ** 2 + (b.y - a.y) ** 2
}
export default class Point {
constructor(x, y) {
this.x = x
this.y = y
}
static distance = distance
}
export { Point as 'module.exports' }
const Point = require('./point.mjs')
console.log(Point) // [class Point]
const { distance } = require('./point.mjs')
console.log(distance) // [Function: distance]
require()
されるモジュールが最上位レベルの await
を含んでいる場合、またはそれが import
するモジュールグラフが最上位レベルの await
を含んでいる場合、ERR_REQUIRE_ASYNC_MODULE
がスローされます。この場合、ユーザーは import()
を使用して非同期モジュールをロードする必要があります。
--experimental-print-required-tla
が有効になっている場合、評価前に ERR_REQUIRE_ASYNC_MODULE
をスローする代わりに、Node.js はモジュールを評価し、最上位レベルの await を特定しようと試み、その場所を出力してユーザーが修正するのに役立ちます。
require()
を使用した ES モジュールの読み込みのサポートは現在実験的なものであり、--no-experimental-require-module
を使用して無効にできます。この機能が使用されている場所を出力するには、--trace-require-module
を使用します。
この機能は、process.features.require_module
が true
であるかどうかを確認することで検出できます。
すべてまとめて
require()
が呼び出されたときにロードされる正確なファイル名を取得するには、require.resolve()
関数を使用します。
上記のすべてをまとめると、require()
が行う処理の高レベルアルゴリズムは擬似コードで次のようになります。
path Y のモジュールから require(X)
1. X がコアモジュールの場合、
a. コアモジュールを返す
b. 終了
2. X が '/' で始まる場合、
a. Y をファイルシステムルートに設定する
3. X が './' または '/' または '../' で始まる場合、
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
c. "not found" をスロー
4. X が '#' で始まる場合、
a. LOAD_PACKAGE_IMPORTS(X, dirname(Y))
5. LOAD_PACKAGE_SELF(X, dirname(Y))
6. LOAD_NODE_MODULES(X, dirname(Y))
7. "not found" をスロー
MAYBE_DETECT_AND_LOAD(X)
1. X が CommonJS モジュールとして解析できる場合、X を CommonJS モジュールとしてロードする。終了。
2. そうでない場合、X のソースコードが
<a href="esm#resolver-algorithm-specification">ESM レゾルバで定義されている DETECT_MODULE_SYNTAX</a> を使用して ECMAScript モジュールとして解析できる場合、
a. X を ECMAScript モジュールとしてロードする。終了。
3. 1. で X を CommonJS として解析しようとしたときの SyntaxError をスローする。終了。
LOAD_AS_FILE(X)
1. X がファイルの場合、X をファイル拡張子形式でロードする。終了
2. X.js がファイルの場合、
a. X に最も近いパッケージスコープ SCOPE を見つける。
b. スコープが見つからなかった場合
1. MAYBE_DETECT_AND_LOAD(X.js)
c. SCOPE/package.json に "type" フィールドが含まれている場合、
1. "type" フィールドが "module" の場合、X.js を ECMAScript モジュールとしてロードする。終了。
2. "type" フィールドが "commonjs" の場合、X.js を CommonJS モジュールとしてロードする。終了。
d. MAYBE_DETECT_AND_LOAD(X.js)
3. X.json がファイルの場合、X.json を JavaScript オブジェクトにロードする。終了
4. X.node がファイルの場合、X.node をバイナリアドオンとしてロードする。終了
LOAD_INDEX(X)
1. X/index.js がファイルの場合
a. X に最も近いパッケージスコープ SCOPE を見つける。
b. スコープが見つからなかった場合、X/index.js を CommonJS モジュールとしてロードする。終了。
c. SCOPE/package.json に "type" フィールドが含まれている場合、
1. "type" フィールドが "module" の場合、X/index.js を ECMAScript モジュールとしてロードする。終了。
2. そうでない場合、X/index.js を CommonJS モジュールとしてロードする。終了。
2. X/index.json がファイルの場合、X/index.json を JavaScript オブジェクトとして解析する。終了
3. X/index.node がファイルの場合、X/index.node をバイナリアドオンとしてロードする。終了
LOAD_AS_DIRECTORY(X)
1. X/package.json がファイルの場合、
a. X/package.json を解析し、"main" フィールドを探す。
b. "main" が偽の値の場合、2. に進む。
c. M = X + (json main フィールド) とする
d. LOAD_AS_FILE(M)
e. LOAD_INDEX(M)
f. LOAD_INDEX(X) 非推奨
g. "not found" をスロー
2. LOAD_INDEX(X)
LOAD_NODE_MODULES(X, START)
1. DIRS = NODE_MODULES_PATHS(START) とする
2. DIRS 内の各 DIR について:
a. LOAD_PACKAGE_EXPORTS(X, DIR)
b. LOAD_AS_FILE(DIR/X)
c. LOAD_AS_DIRECTORY(DIR/X)
NODE_MODULES_PATHS(START)
1. PARTS = path split(START) とする
2. I = PARTS の数 - 1 とする
3. DIRS = [] とする
4. I >= 0 の間、
a. PARTS[I] が "node_modules" の場合、d. に進む。
b. DIR = path join(PARTS[0 .. I] + "node_modules") とする
c. DIRS = DIR + DIRS とする
d. I = I - 1 とする
5. DIRS + GLOBAL_FOLDERS を返す
LOAD_PACKAGE_IMPORTS(X, DIR)
1. DIR に最も近いパッケージスコープ SCOPE を見つける。
2. スコープが見つからなかった場合、戻る。
3. SCOPE/package.json の "imports" が null または undefined の場合、戻る。
4. `--experimental-require-module` が有効な場合
a. CONDITIONS = ["node", "require", "module-sync"] とする
b. そうでない場合、CONDITIONS = ["node", "require"] とする
5. MATCH = PACKAGE_IMPORTS_RESOLVE(X, pathToFileURL(SCOPE),
CONDITIONS) <a href="esm#resolver-algorithm-specification">ESM レゾルバで定義されている</a> とする。
6. RESOLVE_ESM_MATCH(MATCH)。
LOAD_PACKAGE_EXPORTS(X, DIR)
1. X を、名前が @scope/ プレフィックスを持つ可能性があり、サブパスがスラッシュ ('/') で始まる NAME と SUBPATH の組み合わせとして解釈しようとする。
2. X がこのパターンに一致しない場合、または DIR/NAME/package.json がファイルでない場合、戻る。
3. DIR/NAME/package.json を解析し、"exports" フィールドを探す。
4. "exports" が null または undefined の場合、戻る。
5. `--experimental-require-module` が有効な場合
a. CONDITIONS = ["node", "require", "module-sync"] とする
b. そうでない場合、CONDITIONS = ["node", "require"] とする
6. MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(DIR/NAME), "." + SUBPATH,
`package.json` "exports", CONDITIONS) <a href="esm#resolver-algorithm-specification">ESM レゾルバで定義されている</a> とする。
7. RESOLVE_ESM_MATCH(MATCH)
LOAD_PACKAGE_SELF(X, DIR)
1. DIR に最も近いパッケージスコープ SCOPE を見つける。
2. スコープが見つからなかった場合、戻る。
3. SCOPE/package.json の "exports" が null または undefined の場合、戻る。
4. SCOPE/package.json の "name" が X の最初のセグメントでない場合、戻る。
5. MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(SCOPE),
"." + X.slice("name".length), `package.json` "exports", ["node", "require"])
<a href="esm#resolver-algorithm-specification">ESM レゾルバで定義されている</a> とする。
6. RESOLVE_ESM_MATCH(MATCH)
RESOLVE_ESM_MATCH(MATCH)
1. RESOLVED_PATH = fileURLToPath(MATCH) とする
2. RESOLVED_PATH にあるファイルが存在する場合、RESOLVED_PATH をその拡張子形式でロードする。終了
3. "not found" をスロー
キャッシング
モジュールは最初に読み込まれた後にキャッシュされます。これは(他のことの中でも)require('foo')
へのすべての呼び出しが、同じファイルに解決される場合、まったく同じオブジェクトを返すことを意味します。
require.cache
が変更されない限り、require('foo')
への複数回の呼び出しによって、モジュールコードが複数回実行されることはありません。これは重要な機能です。「部分的に完了した」オブジェクトを返すことができるため、循環が発生する場合でも、推移的な依存関係を読み込むことができます。
モジュールコードを複数回実行するには、関数をエクスポートしてその関数を呼び出します。
モジュールキャッシングの注意点
モジュールは、解決されたファイル名に基づいてキャッシュされます。モジュールは呼び出し元のモジュールの場所に基づいて異なるファイル名に解決される可能性があるため、require('foo')
が常にまったく同じオブジェクトを返すとは限りません(異なるファイルに解決される場合)。
さらに、大文字と小文字を区別しないファイルシステムまたはオペレーティングシステムでは、異なる解決済みファイル名が同じファイルを指している可能性がありますが、キャッシュはそれらを異なるモジュールとして扱い、ファイルを複数回再読み込みします。たとえば、require('./foo')
とrequire('./FOO')
は、./foo
と./FOO
が同じファイルであるかどうかに関係なく、2 つの異なるオブジェクトを返します。
組み込みモジュール
[履歴]
バージョン | 変更 |
---|---|
v16.0.0, v14.18.0 | require(...) にnode: インポートのサポートを追加 |
Node.js には、バイナリにコンパイルされたいくつかのモジュールがあります。これらのモジュールについては、このドキュメントの他の場所で詳しく説明されています。
組み込みモジュールは Node.js ソース内で定義されており、lib/
フォルダにあります。
組み込みモジュールはnode:
プレフィックスを使用して識別でき、その場合、require
キャッシュをバイパスします。たとえば、require('node:http')
は、その名前にrequire.cache
エントリが存在する場合でも、常に組み込みの HTTP モジュールを返します。
識別子がrequire()
に渡された場合、一部の組み込みモジュールは常に優先的にロードされます。たとえば、require('http')
は、その名前のファイルが存在する場合でも、常に組み込みの HTTP モジュールを返します。node:
プレフィックスを使用せずにロードできる組み込みモジュールのリストは、module.builtinModules
でプレフィックスなしで表示されます。
node:
プレフィックスが必要な組み込みモジュール
require()
によってロードされる場合、一部の組み込みモジュールはnode:
プレフィックスを付けて要求する必要があります。この要件は、既に名前が取得されているユーザーランドパッケージと、新しく導入された組み込みモジュールとの競合を防ぐためです。現在、node:
プレフィックスを必要とする組み込みモジュールは次のとおりです。
これらのモジュールのリストは、プレフィックスを含めてmodule.builtinModules
に公開されています。
サイクル
循環的な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
のロードが完了し、その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
アプリケーション内で循環モジュール依存関係を正しく動作させるには、慎重な計画が必要です。
ファイルモジュール
正確なファイル名が見つからない場合、Node.js は、.js
、.json
、最後に .node
の拡張子を付加した必要なファイル名の読み込みを試みます。異なる拡張子(例:.cjs
)を持つファイルを読み込む場合、ファイル拡張子を含めた完全な名前を require()
に渡す必要があります(例:require('./file.cjs')
)。
.json
ファイルは JSON テキストファイルとして解析され、.node
ファイルは process.dlopen()
で読み込まれるコンパイル済みアドオンモジュールとして解釈されます。他の拡張子(または拡張子がない)を使用するファイルは、JavaScript テキストファイルとして解析されます。使用する解析目標については、モジュールシステムの決定 セクションを参照してください。
'/'
で始まる必須モジュールは、ファイルへの絶対パスです。たとえば、require('/home/marco/foo.js')
は /home/marco/foo.js
のファイルをロードします。
'./'
で始まる必須モジュールは、require()
を呼び出しているファイルからの相対パスです。つまり、require('./circle')
が circle.js
を見つけるには、circle.js
は foo.js
と同じディレクトリにある必要があります。
ファイルを示す先頭の '/'
、'./'
、または '../'
がない場合、モジュールはコアモジュールであるか、node_modules
フォルダからロードされます。
指定されたパスが存在しない場合、require()
は MODULE_NOT_FOUND
エラーをスローします。
フォルダをモジュールとして
[安定版: 3 - レガシー]
安定版: 3 安定性: 3 - レガシー: 代わりに サブパスエクスポート または サブパスインポート を使用してください。
フォルダを require()
に引数として渡す方法は 3 つあります。
最初の方法は、フォルダのルートに package.json
ファイルを作成し、main
モジュールを指定することです。package.json
ファイルの例を以下に示します。
{ "name": "some-library", "main": "./lib/some-library.js" }
これが ./some-library
のフォルダにあった場合、require('./some-library')
は ./some-library/lib/some-library.js
の読み込みを試みます。
ディレクトリに 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'
上記の 3 つのケースすべてにおいて、import('./some-library')
の呼び出しは ERR_UNSUPPORTED_DIR_IMPORT
エラーになります。パッケージの サブパスエクスポート または サブパスインポート を使用すると、フォルダをモジュールとして使用することと同じ包含組織化の利点を提供し、require
と import
の両方で機能します。
node_modules
フォルダからの読み込み
require()
に渡されるモジュール識別子が組み込みモジュールではなく、'/'
、'../'
、または'./'
で始まらない場合、Node.js は現在のモジュールのディレクトリから開始し、/node_modules
を追加して、その場所からモジュールを読み込もうとします。Node.js は、既に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) {
// モジュールのコードはここにあります
})
これにより、Node.js はいくつかのことを実現します。
var
、const
、またはlet
で定義されたトップレベル変数を、グローバルオブジェクトではなくモジュールにスコープを限定します。- 実際にはモジュールに固有の、グローバルに見えるいくつかの変数を提供するのに役立ちます。たとえば、
- 実装者がモジュールから値をエクスポートするために使用できる
module
およびexports
オブジェクト。 - モジュールの絶対ファイル名とディレクトリパスを含む、便宜的な変数
__filename
と__dirname
。
- 実装者がモジュールから値をエクスポートするために使用できる
モジュールスコープ
__dirname
追加されたバージョン: v0.1.27
現在のモジュールのディレクトリ名。これは、__filename
の path.dirname()
と同じです。
例: /Users/mjr
から node example.js
を実行
console.log(__dirname)
// 出力: /Users/mjr
console.log(path.dirname(__filename))
// 出力: /Users/mjr
__filename
追加されたバージョン: v0.0.1
現在のモジュールのファイル名。これは、シンボリックリンクが解決された現在のモジュールファイルの絶対パスです。
メインプログラムの場合、これはコマンドラインで使用されたファイル名と必ずしも同じではありません。
現在のモジュールのディレクトリ名については、__dirname
を参照してください。
例:
/Users/mjr
から node example.js
を実行
console.log(__filename)
// 出力: /Users/mjr/example.js
console.log(__dirname)
// 出力: /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
追加:v0.1.12
module.exports
への参照で、より短く記述できます。exports
とmodule.exports
の使い分けについては、exports ショートカットに関するセクションを参照してください。
module
追加:v0.1.16
現在のモジュールへの参照です。module
オブジェクトに関するセクションを参照してください。特に、module.exports
はモジュールのエクスポート内容を定義し、require()
を通して利用可能にします。
require(id)
追加:v0.1.13
モジュール、JSON
、ローカルファイルのインポートに使用します。モジュールはnode_modules
からインポートできます。ローカルモジュールと JSON ファイルは、相対パス(例:./
、./foo
、./bar/baz
、../foo
)を使用してインポートできます。このパスは、__dirname
(定義されている場合)または現在の作業ディレクトリを基準に解決されます。POSIX スタイルの相対パスは OS に依存しない方法で解決されるため、上記の例は Windows でも Unix システムと同様に動作します。
// `__dirname`または現在の作業ディレクトリを基準としたパスでローカルモジュールをインポートします。(Windowsでは、これは.\path\myLocalModuleに解決されます。)
const myLocalModule = require('./path/myLocalModule')
// JSONファイルのインポート:
const jsonData = require('./path/filename.json')
// node_modulesまたはNode.js組み込みモジュールのインポート:
const crypto = require('node:crypto')
require.cache
追加:v0.3.0
モジュールは、require
されたときにこのオブジェクトにキャッシュされます。このオブジェクトからキーバリューを削除することで、次のrequire
でモジュールが再読み込みされます。これはネイティブアドオンには適用されず、再読み込みするとエラーが発生します。
エントリの追加や置換も可能です。このキャッシュは組み込みモジュールよりも先にチェックされ、組み込みモジュールに一致する名前がキャッシュに追加された場合、node:
プレフィックス付きのrequire
呼び出しのみが組み込みモジュールを受け取ります。注意して使用してください!
const assert = require('node:assert')
const realFs = require('node:fs')
const fakeFs = {}
require.cache.fs = { exports: fakeFs }
assert.strictEqual(require('fs'), fakeFs)
assert.strictEqual(require('node:fs'), realFs)
require.extensions
追加: v0.3.0
非推奨: v0.10.6 以降
特定のファイル拡張子の処理方法をrequire
に指示します。
.sjs
拡張子のファイルを.js
として処理します。
require.extensions['.sjs'] = require.extensions['.js']
非推奨。 過去には、このリストを使用して、オンデマンドでコンパイルすることにより、Node.js に非 JavaScript モジュールをロードしていました。しかし実際には、他の Node.js プログラムを介してモジュールをロードしたり、事前に JavaScript にコンパイルするなど、はるかに優れた方法があります。
require.extensions
の使用は避けてください。微妙なバグを引き起こす可能性があり、登録された拡張子が増えるごとに拡張子の解決が遅くなります。
require.main
追加: v0.1.17
Node.js プロセスが起動したときにロードされたエントリスクリプトを表すModule
オブジェクト、またはプログラムのエントリポイントが CommonJS モジュールでない場合はundefined
。"メインモジュールのアクセス"を参照してください。
entry.js
スクリプト内:
console.log(require.main)
node entry.js
Module {
id: '.',
path: '/absolute/path/to',
exports: {},
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])
[履歴]
バージョン | 変更点 |
---|---|
v8.9.0 | paths オプションがサポートされるようになりました。 |
v0.3.0 | 追加: v0.3.0 |
request
<string> 解決するモジュールパス。options
<Object>paths
<string[]> モジュール位置を解決するパス。存在する場合、これらのパスはデフォルトの解決パス($HOME/.node_modules
などのGLOBAL_FOLDERSのようなものは常に含まれる)の代わりに使用されます。これらのパスはそれぞれ、モジュール解決アルゴリズムの開始点として使用されます。つまり、node_modules
階層はこの場所からチェックされます。
戻り値: <string>
モジュールの場所を調べるために内部のrequire()
機構を使用しますが、モジュールをロードするのではなく、解決されたファイル名を返すだけです。
モジュールが見つからない場合、MODULE_NOT_FOUND
エラーがスローされます。
require.resolve.paths(request)
追加日: v8.9.0
request
<string> 参照パスを取得するモジュールパス。- 戻り値: <string[]> | <null>
request
の解決中に検索されたパスを含む配列を返します。request
文字列がコアモジュール(例: http
や fs
)を参照する場合は null
を返します。
module
オブジェクト
追加日: v0.1.16
各モジュールにおいて、module
フリー変数は、現在のモジュールを表すオブジェクトへの参照です。便宜上、module.exports
は exports
モジュールグローバルからもアクセスできます。module
は実際にはグローバルではなく、各モジュールにローカルです。
module.children
追加日: v0.1.16
このモジュールによって初めて要求されたモジュールオブジェクト。
module.exports
追加日: v0.1.16
module.exports
オブジェクトは Module
システムによって作成されます。これは必ずしも許容されるものではなく、多くの場合、モジュールをあるクラスのインスタンスにしたいと考えています。そのためには、目的のエクスポートオブジェクトを module.exports
に代入します。目的のオブジェクトを exports
に代入すると、ローカルの exports
変数が単純に再バインドされるだけで、おそらく意図したものではありません。
例えば、a.js
というモジュールを作成する場合:
const EventEmitter = require('node:events')
module.exports = new EventEmitter()
// 何らかの処理を行い、しばらく後に
// モジュール自体から 'ready' イベントをemitします。
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
ショートカット
追加バージョン: v0.1.16
exports
変数は、モジュールのファイルレベルスコープ内で使用可能であり、モジュールが評価される前に module.exports
の値が代入されます。
これにより、module.exports.f = ...
をより簡潔に exports.f = ...
と記述できるショートカットが実現します。ただし、変数と同様に、exports
に新しい値を代入すると、module.exports
にはもはやバインドされなくなることに注意してください。
module.exports.hello = true // モジュールの require からエクスポート
exports = { hello: false } // エクスポートされず、モジュール内でのみ使用可能
module.exports
プロパティが新しいオブジェクトに完全に置き換えられる場合、exports
も再代入するのが一般的です。
module.exports = exports = function Constructor() {
// ... etc.
}
動作を説明するために、require()
の仮説的な実装を想像してみましょう。これは実際に行われている require()
と非常に似ています。
function require(/* ... */) {
const module = { exports: {} }
;((module, exports) => {
// モジュールコードはこちら。この例では、関数を定義します。
function someFunc() {}
exports = someFunc
// この時点で、exports は module.exports のショートカットではなくなり、
// このモジュールは空のデフォルトオブジェクトをエクスポートし続けます。
module.exports = someFunc
// この時点で、モジュールはデフォルトオブジェクトではなく、someFunc をエクスポートするようになります。
})(module, module.exports)
return module.exports
}
module.filename
追加バージョン: v0.1.16
モジュールの完全に解決されたファイル名。
module.id
追加バージョン: v0.1.16
モジュールの識別子。通常、これは完全に解決されたファイル名です。
module.isPreloading
追加バージョン: v15.4.0, v14.17.0
- 型: <boolean> Node.js プリロードフェーズ中にモジュールが実行されている場合
true
。
module.loaded
追加: v0.1.16
モジュールが読み込み完了済みか、読み込み中であるかを表します。
module.parent
追加: v0.1.16
非推奨: v14.6.0, v12.19.0
[安定性: 0 - 非推奨]
安定性: 0 安定性: 0 - 非推奨: require.main
と module.children
を代わりに使用してください。
このモジュールを最初に require したモジュール、または現在のモジュールが現在のプロセスのエントリポイントである場合はnull
、CommonJS モジュールではないもの(例:REPL またはimport
)によってモジュールがロードされた場合はundefined
。
module.path
追加: v11.14.0
モジュールのディレクトリ名。通常はmodule.id
のpath.dirname()
と同じです。
module.paths
追加: v0.4.0
モジュールの検索パス。
module.require(id)
追加: v0.5.1
module.require()
メソッドは、元のモジュールからrequire()
が呼び出されたかのようにモジュールをロードする方法を提供します。
これを行うには、module
オブジェクトへの参照を取得する必要があります。require()
はmodule.exports
を返し、module
は通常特定のモジュールのコード内でのみ使用可能であるため、使用するには明示的にエクスポートする必要があります。
Module
オブジェクト
このセクションは、モジュール: module
コアモジュールに移動されました。
ソースマップ v3 サポート
このセクションは、モジュール: module
コアモジュールに移動されました。