模組:CommonJS 模組#

穩定性:2 - 穩定

CommonJS 模組是封裝 Node.js JavaScript 程式碼的原始方式。Node.js 也支援瀏覽器和其他 JavaScript 執行環境所使用的 ECMAScript 模組 標準。

在 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 載入與 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 函數中的模組會將其區域變數設為私有(請參閱 模組包裝器)。在此範例中,變數 PIcircle.js 的私有變數。

可以將新值(例如函數或物件)指派給 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;
  }
}; 

CommonJS 模組系統實作於 module 核心模組 中。

啟用#

Node.js 有兩個模組系統:CommonJS 模組和 ECMAScript 模組

預設情況下,Node.js 會將下列項目視為 CommonJS 模組

  • 副檔名為 .cjs 的檔案;

  • 當最近的父層 package.json 檔案包含頂層欄位 "type",且其值為 "commonjs" 時,副檔名為 .js 的檔案。

  • 當最近的父層 package.json 檔案不包含頂層欄位 "type",或任何父層資料夾中都沒有 package.json 時,副檔名為 .js 或沒有副檔名的檔案;除非檔案包含語法,否則會發生錯誤,除非將其評估為 ES 模組。套件作者應包含 "type" 欄位,即使在所有來源都是 CommonJS 的套件中也是如此。明確說明套件的 type 會讓建置工具和載入器更輕鬆地判斷如何詮釋套件中的檔案。

  • 具有非 .mjs.cjs.json.node.js 擴充功能的名稱檔案(當最近的父項 package.json 檔案包含頂層欄位 "type",其值為 "module" 時,這些檔案僅在透過 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() 函數的語意旨在夠通用,足以支援合理的目錄結構。套件管理員程式,例如 dpkgrpmnpm,有望可以從 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_modules/<name>/<version> 中,而不是直接放在 /usr/lib/node 中。這樣,Node.js 就不用在 /usr/node_modules/node_modules 中尋找遺失的相依性。

為了讓模組可供 Node.js REPL 使用,也可以將 /usr/lib/node_modules 資料夾新增到 $NODE_PATH 環境變數中。由於使用 node_modules 資料夾的模組查詢都是相對的,而且基於呼叫 require() 的檔案的實際路徑,因此套件本身可以放在任何地方。

.mjs 擴充功能#

由於 require() 的同步性質,無法使用它來載入 ECMAScript 模組檔案。嘗試執行此動作會擲回 ERR_REQUIRE_ESM 錯誤。請改用 import()

.mjs 擴充功能保留給無法透過 require() 載入的 ECMAScript 模組。請參閱 判定模組系統 部分,以取得關於哪些檔案會被剖析為 ECMAScript 模組的更多資訊。

全部一起#

若要取得呼叫 require() 時將載入的確切檔案名稱,請使用 require.resolve() 函式。

將上述所有內容彙整起來,以下是 require() 執行的偽程式碼高階演算法

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 file system root
3. If X begins with './' or '/' or '../'
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
   c. THROW "not found"
4. If X begins with '#'
   a. LOAD_PACKAGE_IMPORTS(X, dirname(Y))
5. LOAD_PACKAGE_SELF(X, dirname(Y))
6. LOAD_NODE_MODULES(X, dirname(Y))
7. THROW "not found"

LOAD_AS_FILE(X)
1. If X is a file, load X as its file extension format. 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. If "main" is a falsy value, GOTO 2.
   c. let M = X + (json main field)
   d. LOAD_AS_FILE(M)
   e. LOAD_INDEX(M)
   f. LOAD_INDEX(X) DEPRECATED
   g. THROW "not found"
2. LOAD_INDEX(X)

LOAD_NODE_MODULES(X, START)
1. let DIRS = NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
   a. LOAD_PACKAGE_EXPORTS(X, DIR)
   b. LOAD_AS_FILE(DIR/X)
   c. 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 = []
4. while I >= 0,
   a. if PARTS[I] = "node_modules" CONTINUE
   b. DIR = path join(PARTS[0 .. I] + "node_modules")
   c. DIRS = DIR + DIRS
   d. let I = I - 1
5. return DIRS + GLOBAL_FOLDERS

LOAD_PACKAGE_IMPORTS(X, DIR)
1. Find the closest package scope SCOPE to DIR.
2. If no scope was found, return.
3. If the SCOPE/package.json "imports" is null or undefined, return.
4. let MATCH = PACKAGE_IMPORTS_RESOLVE(X, pathToFileURL(SCOPE),
  ["node", "require"]) defined in the ESM resolver.
5. RESOLVE_ESM_MATCH(MATCH).

LOAD_PACKAGE_EXPORTS(X, DIR)
1. Try to interpret X as a combination of NAME and SUBPATH where the name
   may have a @scope/ prefix and the subpath begins with a slash (`/`).
2. If X does not match this pattern or DIR/NAME/package.json is not a file,
   return.
3. Parse DIR/NAME/package.json, and look for "exports" field.
4. If "exports" is null or undefined, return.
5. let MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(DIR/NAME), "." + SUBPATH,
   `package.json` "exports", ["node", "require"]) defined in the ESM resolver.
6. RESOLVE_ESM_MATCH(MATCH)

LOAD_PACKAGE_SELF(X, DIR)
1. Find the closest package scope SCOPE to DIR.
2. If no scope was found, return.
3. If the SCOPE/package.json "exports" is null or undefined, return.
4. If the SCOPE/package.json "name" is not the first segment of X, return.
5. let MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(SCOPE),
   "." + X.slice("name".length), `package.json` "exports", ["node", "require"])
   defined in the ESM resolver.
6. RESOLVE_ESM_MATCH(MATCH)

RESOLVE_ESM_MATCH(MATCH)
1. let RESOLVED_PATH = fileURLToPath(MATCH)
2. If the file at RESOLVED_PATH exists, load RESOLVED_PATH as its extension
   format. STOP
3. THROW "not found"

快取#

模組會在第一次載入後快取。這表示(除其他事項外)每個對 require('foo') 的呼叫都會取得完全相同的回傳物件,如果它會解析為相同的檔案。

只要未修改 require.cache,對 require('foo') 的多次呼叫不會導致模組程式碼被執行多次。這項功能很重要。有了它,就可以回傳「部分完成」的物件,因此即使會造成循環,也可以載入傳遞相依性。

若要讓模組執行程式碼多次,請匯出函式,並呼叫該函式。

模組快取注意事項#

模組會根據其已解析的檔案名稱進行快取。由於模組可能會根據呼叫模組的位置(從 node_modules 資料夾載入)解析為不同的檔案名稱,因此無法保證 require('foo') 始終會傳回完全相同的物件,如果它解析為不同的檔案。

此外,在不區分大小寫的檔案系統或作業系統上,不同的已解析檔案名稱可能會指向同一個檔案,但快取仍會將它們視為不同的模組,並會多次重新載入檔案。例如,require('./foo')require('./FOO') 會傳回兩個不同的物件,無論 ./foo./FOO 是否為同一個檔案。

核心模組#

Node.js 已將多個模組編譯至二進位檔中。這些模組在本文件中的其他地方有更詳細的說明。

核心模組在 Node.js 來源中定義,並位於 lib/ 資料夾中。

可以使用 node: 前綴識別核心模組,這樣它就會繞過 require 快取。例如,require('node:http') 始終會傳回內建的 HTTP 模組,即使有同名的 require.cache 項目。

如果將其識別碼傳遞給 require(),則某些核心模組始終會優先載入。例如,require('http') 始終會傳回內建的 HTTP 模組,即使有同名的檔案。可以使用 module.builtinModules 顯示不使用 node: 前綴即可載入的核心模組清單。

循環#

當有循環的 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() 的檔案。也就是說,circle.js 必須與 foo.js 在同一個目錄中,require('./circle') 才能找到它。

如果沒有前導的 '/''./''../' 來表示檔案,則模組必須是核心模組,或從 node_modules 資料夾載入。

如果給定的路徑不存在,require() 將會拋出 MODULE_NOT_FOUND 錯誤。

資料夾作為模組#

有三個方式可以將資料夾作為引數傳遞給 require()

第一個方式是在資料夾的根目錄建立一個 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.jsindex.node 檔案。例如,如果在先前的範例中沒有 package.json 檔案,則 require('./some-library') 會嘗試載入

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

如果這些嘗試失敗,則 Node.js 會使用預設錯誤將整個模組報告為遺失

Error: Cannot find module 'some-library' 

在以上三種情況中,import('./some-library') 呼叫都會導致 ERR_UNSUPPORTED_DIR_IMPORT 錯誤。使用套件 子路徑匯出子路徑匯入 可以提供與資料夾作為模組相同的封裝組織優點,而且適用於 requireimport

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) {
// Module code actually lives in here
}); 

透過這樣做,Node.js 達到了幾個目的

  • 它讓頂層變數(使用 varconstlet 定義)的範圍侷限於模組,而不是全域物件。
  • 它有助於提供一些實際上特定於模組的全域變數,例如
    • moduleexports 物件,實作人員可以使用它們來從模組匯出值。
    • 方便的變數 __filename__dirname,包含模組的絕對檔名和目錄路徑。

模組範圍#

__dirname#

目前模組的目錄名稱。這與 path.dirname()__filename 相同。

範例:從 /Users/mjr 執行 node example.js

console.log(__dirname);
// Prints: /Users/mjr
console.log(path.dirname(__filename));
// Prints: /Users/mjr 

__filename#

目前模組的檔名。這是目前模組檔案的絕對路徑,其中符號連結已解析。

對於主程式而言,這不一定與命令列中使用的檔案名稱相同。

請參閱 __dirname 以取得目前模組的目錄名稱。

範例

/Users/mjr 執行 node example.js

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

假設有兩個模組:ab,其中 ba 的相依模組,且目錄結構如下:

  • /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 快捷方式 部分,以了解何時使用 exports,何時使用 module.exports

module#

對目前模組的參照,請參閱 module 物件 部分。特別是,module.exports 用於定義模組匯出什麼,並透過 require() 提供。

require(id)#

用於匯入模組、JSON 和本機檔案。模組可以從 node_modules 匯入。本機模組和 JSON 檔案可以使用相對路徑 (例如 ././foo./bar/baz../foo) 進行匯入,這些路徑將根據由 __dirname (如果已定義) 或目前工作目錄所指定的目錄進行解析。POSIX 風格的相對路徑會以作業系統無關的方式進行解析,這表示上述範例在 Windows 上的運作方式會與在 Unix 系統上的運作方式相同。

// Importing a local module with a path relative to the `__dirname` or current
// working directory. (On Windows, this would resolve to .\path\myLocalModule.)
const myLocalModule = require('./path/myLocalModule');

// Importing a JSON file:
const jsonData = require('./path/filename.json');

// Importing a module from node_modules or Node.js built-in module:
const crypto = require('node:crypto'); 
require.cache#

當模組被需要時,它們會快取在此物件中。透過刪除此物件中的金鑰值,下一個 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#

穩定性:0 - 已停用

指示 require 如何處理特定檔案副檔名。

將副檔名為 .sjs 的檔案視為 .js 檔案處理

require.extensions['.sjs'] = require.extensions['.js']; 

已停用。過去,此清單用於將非 JavaScript 模組載入 Node.js,並依需要進行編譯。然而,實際上,有更好的方法可以做到這一點,例如透過其他 Node.js 程式載入模組,或事先將它們編譯為 JavaScript。

避免使用 require.extensions。使用可能會導致細微的錯誤,而且隨著每個註冊的擴充功能,解析擴充功能的速度也會變慢。

require.main#

Module 物件,代表 Node.js 程序啟動時載入的進入腳本,或如果程序的進入點不是 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])#
  • request <string> 要解析的模組路徑。
  • options <Object>
    • paths <string[]> 從中解析模組位置的路徑。如果存在,這些路徑會用於取代預設解析路徑,但例外情況為 GLOBAL_FOLDERS,例如 $HOME/.node_modules,這些路徑總是會包含在內。這些路徑中的每個路徑都會用作模組解析演算法的起點,這表示會從這個位置檢查 node_modules 層級。
  • 傳回:<string>

使用內部 require() 機制來查找模組的位置,但不是載入模組,而是傳回已解析的檔案名稱。

如果找不到模組,就會擲回 MODULE_NOT_FOUND 錯誤。

require.resolve.paths(request)#

傳回一個陣列,其中包含在解析 request 期間搜尋的路徑,或如果 request 字串參照核心模組(例如 httpfs),則傳回 null

module 物件#

在每個模組中,module 自由變數是參照表示目前模組的物件。為了方便,module.exports 也可透過 exports 模組全域變數存取。module 實際上並非全域變數,而是每個模組的區域變數。

module.children#

這個模組第一次需要的模組物件。

module.exports#

module.exports 物件是由 Module 系統建立的。有時這無法接受;許多人希望他們的模組是某個類別的執行個體。若要執行此動作,請將所需的匯出物件指定給 module.exports。將所需的物件指定給 exports 只會重新繫結區域 exports 變數,這可能不是想要的結果。

例如,假設我們正在製作一個名為 a.js 的模組

const EventEmitter = require('node: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 = ...。不過,請注意,就像任何變數一樣,如果指派新值給 exports,它就不再與 module.exports 繫結

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

module.exports 屬性完全被新物件取代時,通常也會重新指派 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.isPreloading#

  • 類型:<boolean> 如果模組在 Node.js 預載入階段執行,則為 true

module.loaded#

模組是否已載入完成,或正在載入中。

module.parent#

穩定性:0 - 已不建議使用:請改用 require.mainmodule.children

需要此模組的第一個模組,或如果目前的模組是目前程序的進入點,則為 null,或如果模組是由非 CommonJS 模組 (例如:REPL 或 import) 載入,則為 undefined

module.path#

模組的目錄名稱。這通常與 module.idpath.dirname() 相同。

module.paths#

模組的搜尋路徑。

module.require(id)#

module.require() 方法提供一種載入模組的方式,就好像 require() 是從原始模組呼叫的一樣。

為了執行此操作,必須取得 module 物件的參考。由於 require() 會傳回 module.exports,而 module 通常在特定模組的程式碼中可用,因此必須明確地匯出它才能使用。

Module 物件#

此區段已移至 模組:module 核心模組

來源地圖 v3 支援#

此區段已移至 模組:module 核心模組