Node.js v26.0.0 說明文件
- Node.js v26.0.0
- 目錄
- 索引
- 關於此說明文件
- 用法與範例
- 斷言測試
- 非同步內容追蹤
- Async hooks
- Buffer
- C++ 擴充套件
- 使用 Node-API 的 C/C++ 擴充套件
- C++ 嵌入器 API
- 子程序
- 叢集
- 命令列選項
- Console
- Crypto
- 除錯器
- 棄用的 API
- Diagnostics Channel
- DNS
- 網域 (Domain)
- 環境變數
- 錯誤
- 事件
- 檔案系統
- 全域變數
- HTTP
- HTTP/2
- HTTPS
- 檢查器
- 國際化
- 模組:CommonJS 模組
- 模組:ECMAScript 模組
- 模組:
node:moduleAPI - 模組:套件
- 模組:TypeScript
- Net
- Iterable Streams API
- OS
- Path
- 效能勾子 (Performance hooks)
- 權限
- 程序
- Punycode
- 查詢字串
- Readline
- REPL
- 報告
- 單一可執行應用程式
- SQLite
- Stream
- 字串解碼器
- 測試執行器
- 計時器
- TLS/SSL
- 追蹤事件
- TTY
- UDP/資料報
- URL
- 公用工具
- V8
- VM
- WASI
- Web Crypto API
- Web Streams API
- 工作執行緒
- Zlib
- Zlib 可反覆運算壓縮
- 其他版本
- 選項
模組:ECMAScript 模組#
穩定度:2 - 穩定
簡介#
ECMAScript 模組是封裝 JavaScript 程式碼以供重複使用的 官方標準格式。模組使用各種 import 和 export 陳述式定義。
以下 ES 模組範例導出了一個函式
// addTwo.mjs
function addTwo(num) {
return num + 2;
}
export { addTwo };
以下 ES 模組範例從 addTwo.mjs 匯入了該函式
// app.mjs
import { addTwo } from './addTwo.mjs';
// Prints: 6
console.log(addTwo(4));
Node.js 完全支援當前規範中的 ECMAScript 模組,並提供它們與其原始模組格式 CommonJS 之間的互操作性。
啟用#
Node.js 擁有兩種模組系統:CommonJS 模組與 ECMAScript 模組。
開發者可以透過 .mjs 副檔名、package.json 中設為 "module" 的 "type" 欄位,或設為 "module" 的 --input-type 旗標,告訴 Node.js 將 JavaScript 解釋為 ES 模組。這些都是程式碼意圖以 ES 模組運行的明確標記。
相反地,開發者可以透過 .cjs 副檔名、package.json 中設為 "commonjs" 的 "type" 欄位,或設為 "commonjs" 的 --input-type 旗標,明確告訴 Node.js 將 JavaScript 解釋為 CommonJS。
當程式碼缺乏任何模組系統的明確標記時,Node.js 將檢查模組的原始程式碼以尋找 ES 模組語法。若發現此類語法,Node.js 將以 ES 模組執行該程式碼;否則將以 CommonJS 運行。詳情請參閱 確定模組系統。
套件 (Packages)#
本節已移至 模組:套件。
import 指定符#
術語#
import 陳述式的指定符是 from 關鍵字之後的字串,例如 import { sep } from 'node:path' 中的 'node:path'。指定符也用於 export from 陳述式,並作為 import() 表達式的引數。
指定符有三種類型:
-
相對指定符:如
'./startup.js'或'../config.mjs'。它們參照相對於匯入檔案位置的路徑。對於這些指定符,副檔名總是必要的。 -
裸指定符 (Bare specifiers):如
'some-package'或'some-package/shuffle'。它們可以透過套件名稱參照套件的主進入點,或根據範例參照套件內以套件名稱為字首的特定功能模組。僅在沒有"exports"欄位的套件中,才需要包含副檔名。 -
絕對指定符:如
'file:///opt/nodejs/config.js'。它們直接且明確地參照完整路徑。
裸指定符的解析由 Node.js 模組解析與載入演算法處理。所有其他指定符的解析總是僅使用標準的相對 URL 解析語意。
與 CommonJS 一樣,套件內的模組檔案可以透過在套件名稱後附加路徑來存取,除非套件的 package.json 包含 "exports" 欄位。在這種情況下,套件內的檔案只能透過 "exports" 定義的路徑存取。
關於適用於 Node.js 模組解析中裸指定符的套件解析規則詳情,請參閱 套件文件。
強制性副檔名#
使用 import 關鍵字解析相對或絕對指定符時,必須提供副檔名。目錄索引(例如 './startup/index.js')也必須完整指定。
此行為符合瀏覽器環境中 import 的運作方式(假設伺服器配置正常)。
URLs#
ES 模組以 URL 形式解析與快取。這意味著特殊字元必須進行 百分比編碼 (percent-encoded),例如 # 編碼為 %23,? 編碼為 %3F。
支援 file:、node: 和 data: URL 協定。Node.js 原生不支援像 'https://example.com/app.js' 這樣的指定符,除非使用 自訂 HTTPS 載入器。
file: URLs#
如果用於解析它們的 import 指定符具有不同的查詢字串或片段,模組將會被載入多次。
import './foo.mjs?query=1'; // loads ./foo.mjs with query of "?query=1"
import './foo.mjs?query=2'; // loads ./foo.mjs with query of "?query=2"
磁碟區根目錄可透過 /、// 或 file:/// 參照。鑒於 URL 與路徑解析之間的差異(例如百分比編碼細節),建議在匯入路徑時使用 url.pathToFileURL。
data: 匯入#
支援使用以下 MIME 類型的 data: URLs 進行匯入:
text/javascript(用於 ES 模組)application/json(用於 JSON)application/wasm(用於 Wasm)
import 'data:text/javascript,console.log("hello!");';
import _ from 'data:application/json,"world!"' with { type: 'json' };
data: URLs 僅能解析內建模組的 裸指定符 和 絕對指定符。解析 相對指定符 無效,因為 data: 不是 特殊協定 (special scheme)。例如,嘗試從 data:text/javascript,import "./foo"; 載入 ./foo 會解析失敗,因為 data: URLs 沒有相對解析的概念。
node: 匯入#
支援使用 node: URLs 作為載入 Node.js 內建模組的替代方式。此 URL 協定允許透過有效的絕對 URL 字串來參照內建模組。
import fs from 'node:fs/promises';
匯入屬性#
匯入屬性 是模組匯入陳述式的一種內聯語法,用於在模組指定符之外傳遞更多資訊。
import fooData from './foo.json' with { type: 'json' };
const { default: barData } =
await import('./bar.json', { with: { type: 'json' } });
Node.js 僅支援 type 屬性,且支援以下值:
屬性 type |
用途 |
|---|---|
'json' |
JSON 模組 |
匯入 JSON 模組時,type: 'json' 屬性是強制性的。
內建模組#
內建模組 提供其公共 API 的具名匯出 (named exports)。同時也提供預設匯出 (default export),即 CommonJS 匯出的值。預設匯出可用於修改具名匯出等操作。內建模組的具名匯出僅透過呼叫 module.syncBuiltinESMExports() 進行更新。
import EventEmitter from 'node:events';
const e = new EventEmitter();
import { readFile } from 'node:fs';
readFile('./foo.txt', (err, source) => {
if (err) {
console.error(err);
} else {
console.log(source);
}
});
import fs, { readFileSync } from 'node:fs';
import { syncBuiltinESMExports } from 'node:module';
import { Buffer } from 'node:buffer';
fs.readFileSync = () => Buffer.from('Hello, ESM');
syncBuiltinESMExports();
fs.readFileSync === readFileSync;
匯入內建模組時,即使未個別存取,所有的具名匯出(即模組匯出物件的屬性)都會被填充。這可能使內建模組的初始匯入比使用
require()或process.getBuiltinModule()稍慢。後者中,模組匯出物件會立即求值,但某些屬性可能僅在首次單獨存取時才初始化。
import() 表達式#
動態 import() 提供了一種非同步匯入模組的方式。它在 CommonJS 和 ES 模組中均受支援,且可用於載入 CommonJS 和 ES 模組。
import.meta#
- 類型:
<Object>
import.meta 元屬性是一個包含以下屬性的 Object。僅在 ES 模組中受支援。
import.meta.dirname#
- 類型:
<string>當前模組的目錄名稱。
這與 import.meta.filename 的 path.dirname() 相同。
注意:僅存在於
file:模組上。
import.meta.filename#
- 類型:
<string>當前模組的完整絕對路徑與檔名,並已解析符號連結。
這與 import.meta.url 的 url.fileURLToPath() 相同。
注意:僅本地模組支援此屬性。不使用
file:協定的模組不會提供它。
import.meta.url#
- 類型:
<string>該模組的絕對file:URL。
其定義與瀏覽器中提供當前模組檔案 URL 的方式完全相同。
這啟用了諸如相對檔案載入等有用的模式。
import { readFileSync } from 'node:fs';
const buffer = readFileSync(new URL('./data.proto', import.meta.url));
import.meta.main#
穩定度:1.0 - 早期開發階段
- 類型:
<boolean>當前模組為當前處理程序的進入點時為true,否則為false。
等同於 CommonJS 中的 require.main === module。
類似於 Python 的 __name__ == "__main__"。
export function foo() {
return 'Hello, world';
}
function main() {
const message = foo();
console.log(message);
}
if (import.meta.main) main();
// `foo` can be imported from another module without possible side-effects from `main`
import.meta.resolve(specifier)#
穩定度:1.2 - 發行候選版 (Release candidate)
import.meta.resolve 是一個針對每個模組範圍的模組相對解析函式,並回傳 URL 字串。
const dependencyAsset = import.meta.resolve('component-lib/asset.css');
// file:///app/node_modules/component-lib/asset.css
import.meta.resolve('./dep.js');
// file:///app/dep.js
支援 Node.js 模組解析的所有功能。依賴項解析受限於套件內允許的匯出解析。
注意事項:
- 這可能會導致同步檔案系統操作,進而影響效能,類似於
require.resolve。 - 此功能在自訂載入器中不可用(會造成死鎖)。
非標準 API:
使用 --experimental-import-meta-resolve 旗標時,該函式接受第二個引數:
與 CommonJS 的互操作性#
import 陳述式#
import 陳述式可以參照 ES 模組或 CommonJS 模組。import 陳述式僅允許在 ES 模組中使用,但 CommonJS 支援動態 import() 表達式來載入 ES 模組。
匯入 CommonJS 模組時,module.exports 物件會作為預設匯出提供。具名匯出可透過靜態分析作為便利功能提供,以獲得更好的生態系統相容性。
require#
CommonJS 模組的 require 目前僅支援載入同步 ES 模組(即不使用頂層 await 的 ES 模組)。
CommonJS 命名空間#
CommonJS 模組由一個可以是任何類型的 module.exports 物件組成。
為了支援這一點,當從 ECMAScript 模組匯入 CommonJS 時,會為 CommonJS 模組建構一個命名空間封裝器,它總是提供一個指向 CommonJS module.exports 值的 default 匯出鍵。
此外,會對 CommonJS 模組的原始程式碼執行啟發式靜態分析,以取得最佳嘗試的靜態匯出列表,提供在基於 module.exports 值的命名空間上。這是必要的,因為這些命名空間必須在 CJS 模組求值之前建構。
這些 CommonJS 命名空間物件也提供 default 匯出作為 'module.exports' 具名匯出,以明確表示其在 CommonJS 中的表示使用此值,而非命名空間值。這反映了 require(esm) 互操作支援中處理 'module.exports' 匯出名稱的語意。
匯入 CommonJS 模組時,可以使用 ES 模組的預設匯入或其對應的語法糖可靠地進行匯入。
import { default as cjs } from 'cjs';
// Identical to the above
import cjsSugar from 'cjs';
console.log(cjs);
console.log(cjs === cjsSugar);
// Prints:
// <module.exports>
// true
此模組命名空間奇異物件 (Module Namespace Exotic Object) 可在使用 import * as m from 'cjs' 或動態匯入時直接觀察到。
import * as m from 'cjs';
console.log(m);
console.log(m === await import('cjs'));
// Prints:
// [Module] { default: <module.exports>, 'module.exports': <module.exports> }
// true
為了與 JS 生態系統中的現有用法有更好的相容性,Node.js 此外還會嘗試確定每個已匯入 CommonJS 模組的具名匯出,並透過靜態分析過程將它們作為獨立的 ES 模組匯出提供。
例如,考慮一個寫入的 CommonJS 模組:
// cjs.cjs
exports.name = 'exported';
上述模組支援 ES 模組中的具名匯入。
import { name } from './cjs.cjs';
console.log(name);
// Prints: 'exported'
import cjs from './cjs.cjs';
console.log(cjs);
// Prints: { name: 'exported' }
import * as m from './cjs.cjs';
console.log(m);
// Prints:
// [Module] {
// default: { name: 'exported' },
// 'module.exports': { name: 'exported' },
// name: 'exported'
// }
從 Module Namespace Exotic Object 被紀錄的最後一個範例可以看出,當模組匯入時,name 匯出會從 module.exports 物件複製並直接設定在 ES 模組命名空間上。
對於這些具名匯出,不會偵測到即時綁定 (live binding) 更新或新增至 module.exports 的新匯出。
具名匯出的偵測基於常見的語法模式,但並不總是能正確偵測。在這種情況下,使用上述的預設匯入形式可能是更好的選擇。
具名匯出偵測涵蓋了許多常見的匯出模式、重新匯出模式以及建置工具和轉譯器的輸出。請參閱 merve 以了解所實作的精確語意。
ES 模組與 CommonJS 的差異#
沒有 require、exports 或 module.exports#
在大多數情況下,ES 模組的 import 可用於載入 CommonJS 模組。
若有需要,可以使用 module.createRequire() 在 ES 模組內建構 require 函式。
沒有 __filename 或 __dirname#
這些 CommonJS 變數在 ES 模組中不可用。
__filename 和 __dirname 的使用案例可透過 import.meta.filename 和 import.meta.dirname 來複製。
不支援載入 Addon#
Addons 目前不支援 ES 模組匯入。
它們可以改用 module.createRequire() 或 process.dlopen 來載入。
沒有 require.main#
若要取代 require.main === module,可以使用 import.meta.main API。
沒有 require.resolve#
相對解析可透過 new URL('./local', import.meta.url) 處理。
若要完全取代 require.resolve,可以使用 import.meta.resolve API。
或者,也可以使用 module.createRequire()。
沒有 NODE_PATH#
NODE_PATH 不參與解析 import 指定符。若需此功能,請使用符號連結。
沒有 require.extensions#
require.extensions 不會被 import 使用。模組自訂掛鉤可以提供替代方案。
沒有 require.cache#
require.cache 不會被 import 使用,因為 ES 模組載入器有其獨立的快取。
JSON 模組#
JSON 檔案可以透過 import 參照。
import packageConfig from './package.json' with { type: 'json' };
with { type: 'json' } 語法是強制性的;請參閱 匯入屬性。
匯入的 JSON 僅公開一個 default 匯出。不支援具名匯出。CommonJS 快取中會建立一個快取條目以避免重複。若 JSON 模組已從相同路徑匯入,則 CommonJS 中將回傳相同的物件。
Wasm 模組#
支援匯入 WebAssembly 模組執行個體 (instances) 以及 WebAssembly 原始碼階段匯入。
這兩項整合皆符合 WebAssembly 的 ES 模組整合提案。
Wasm 原始碼階段匯入#
穩定度:1.2 - 發行候選版 (Release candidate)
原始碼階段匯入 (Source Phase Imports) 提案允許 import source 關鍵字組合直接匯入 WebAssembly.Module 物件,而非獲取已透過其依賴項實例化的模組執行個體。
當需要對 Wasm 進行自訂實例化,同時仍透過 ES 模組整合進行解析和載入時,這很有用。
例如,若要建立模組的多個執行個體,或將自訂匯入傳遞至 library.wasm 的新執行個體:
import source libraryModule from './library.wasm';
const instance1 = await WebAssembly.instantiate(libraryModule, importObject1);
const instance2 = await WebAssembly.instantiate(libraryModule, importObject2);
除了靜態原始碼階段外,還有透過 import.source 動態相位匯入語法實現的動態原始碼階段變體:
const dynamicLibrary = await import.source('./library.wasm');
const instance = await WebAssembly.instantiate(dynamicLibrary, importObject);
JavaScript 字串內建函式#
穩定度:1.2 - 發行候選版 (Release candidate)
匯入 WebAssembly 模組時,WebAssembly JS 字串內建函式提案 會透過 ESM 整合自動啟用。這允許 WebAssembly 模組直接從 wasm:js-string 命名空間使用高效的編譯時期字串內建函式。
例如,以下 Wasm 模組使用 wasm:js-string 的 length 內建函式導出了字串 getLength 函式:
(module
;; Compile-time import of the string length builtin.
(import "wasm:js-string" "length" (func $string_length (param externref) (result i32)))
;; Define getLength, taking a JS value parameter assumed to be a string,
;; calling string length on it and returning the result.
(func $getLength (param $str externref) (result i32)
local.get $str
call $string_length
)
;; Export the getLength function.
(export "getLength" (func $get_length))
)
import { getLength } from './string-len.wasm';
getLength('foo'); // Returns 3.
Wasm 內建函式是編譯時期的匯入,在模組編譯期間而非實例化期間連結。它們的行為不像正常的模組圖匯入,且無法透過 WebAssembly.Module.imports(mod) 檢視,除非使用停用字串內建功能的 WebAssembly.compile API 重新編譯模組。
字串常數也可以從 wasm:js/string-constants 內建匯入 URL 匯入,允許定義靜態 JS 字串全域變數:
(module
(import "wasm:js/string-constants" "hello" (global $hello externref))
)
在實例化之前於原始碼階段匯入模組,也會自動使用編譯時期內建函式。
import source mod from './string-len.wasm';
const { exports: { getLength } } = await WebAssembly.instantiate(mod, {});
getLength('foo'); // Also returns 3.
Wasm 執行個體階段匯入#
穩定性:1.1 - 積極開發中
執行個體匯入允許將任何 .wasm 檔案匯入為一般模組,進而支援其模組匯入。
例如,一個包含以下內容的 index.js:
import * as M from './library.wasm';
console.log(M);
執行於:
node index.mjs
將提供用於 library.wasm 實例化的匯出介面。
保留的 Wasm 命名空間#
匯入 WebAssembly 模組執行個體時,它們不能使用以保留前綴開頭的匯入模組名稱或匯入/匯出名稱:
wasm-js:- 在所有模組匯入名稱、模組名稱和匯出名稱中保留。wasm:- 在模組匯入名稱和匯出名稱中保留(為了支援未來的內建 Polyfill,允許使用匯入的模組名稱)。
使用上述保留名稱匯入模組將拋出 WebAssembly.LinkError。
頂層 await#
await 關鍵字可用於 ECMAScript 模組的頂層主體中。
假設一個 a.mjs 包含:
export const five = await Promise.resolve(5);
以及一個 b.mjs 包含:
import { five } from './a.mjs';
console.log(five); // Logs `5`
node b.mjs # works
如果頂層 await 表達式永不解析,node 處理程序將以 13 狀態碼退出。
import { spawn } from 'node:child_process';
import { execPath } from 'node:process';
spawn(execPath, [
'--input-type=module',
'--eval',
// Never-resolving Promise:
'await new Promise(() => {})',
]).once('exit', (code) => {
console.log(code); // Logs `13`
});
載入器 (Loaders)#
之前的載入器文件現位於 模組:自訂掛鉤。
解析與載入演算法#
特性#
預設解析器具有以下屬性:
- 使用 FileURL 的解析(如 ES 模組所用)
- 相對與絕對 URL 解析
- 無預設副檔名
- 無資料夾主進入點 (folder mains)
- 透過 node_modules 進行裸指定符套件解析查詢
- 對未知副檔名或協定不會失敗
- 可選擇向載入階段提供格式提示
預設載入器具有以下屬性:
- 支援透過
node:URLs 進行內建模組載入 - 支援透過
data:URLs 進行「內聯」模組載入 - 支援
file:模組載入 - 對任何其他 URL 協定失敗
- 對
file:載入的未知副檔名失敗(僅支援.cjs、.js和.mjs)
解析演算法#
載入 ES 模組指定符的演算法透過下方的 ESM_RESOLVE 方法給出。它回傳相對於 parentURL 的模組指定符的解析後 URL。
解析演算法確定模組載入的完整解析後 URL,以及建議的模組格式。解析演算法不確定解析後的 URL 協定是否可載入,或副檔名是否被允許;這些驗證由 Node.js 在載入階段應用(例如,若被要求載入非 file:、data: 或 node: 協定的 URL)。
該演算法也會嘗試根據副檔名確定檔案格式(參見下方的 ESM_FILE_FORMAT 演算法)。若它不識別副檔名(例如若不是 .mjs、.cjs 或 .json),則回傳 undefined 的格式,這會在載入階段拋出錯誤。
確定解析後 URL 模組格式的演算法由 ESM_FILE_FORMAT 提供,它為任何檔案回傳唯一的模組格式。對於 ECMAScript 模組,回傳 "module" 格式,而 "commonjs" 格式用於指示透過舊版 CommonJS 載入器載入。未來更新中可能會擴展諸如 "addon" 的額外格式。
在以下演算法中,除非另有說明,所有子常式錯誤都會傳播為這些頂層常式的錯誤。
defaultConditions 是條件環境名稱陣列,["node", "import"]。
解析器可以拋出以下錯誤:
- Invalid Module Specifier:模組指定符是無效的 URL、套件名稱或套件子路徑指定符。
- Invalid Package Configuration:package.json 設定無效或包含無效設定。
- Invalid Package Target:套件的匯出或匯入定義了類型無效或字串目標無效的目標模組。
- Package Path Not Exported:套件匯出未定義或未允許給定模組的套件子路徑。
- Package Import Not Defined:套件匯入未定義該指定符。
- Module Not Found:所請求的套件或模組不存在。
- Unsupported Directory Import:解析後的路徑對應到一個目錄,這不是模組匯入支援的目標。
解析演算法規範#
ESM_RESOLVE(specifier, parentURL)
- 設 resolved 為 undefined。
- 若 specifier 是有效的 URL,則:
- 將 resolved 設為解析並重新序列化 specifier 為 URL 的結果。
- 否則,若 specifier 以 "/"、"./" 或 "../" 開頭,則:
- 將 resolved 設為相對於 parentURL 的 specifier URL 解析結果。
- 否則,若 specifier 以 "#" 開頭,則:
- 將 resolved 設為 PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, defaultConditions) 的結果。
- 否則:
- 註:specifier 現在是一個裸指定符。
- 將 resolved 設為 PACKAGE_RESOLVE(specifier, parentURL) 的結果。
- 設 format 為 undefined。
- 若 resolved 是 "file:" URL,則:
- 若 resolved 包含任何 "/" 或 "\" 的百分比編碼(分別為 "%2F" 和 "%5C"),則:
- 拋出 Invalid Module Specifier 錯誤。
- 若 resolved 的檔案是一個目錄,則:
- 拋出 Unsupported Directory Import 錯誤。
- 若 resolved 的檔案不存在,則:
- 拋出 Module Not Found 錯誤。
- 將 resolved 設為 resolved 的真實路徑,保持相同的 URL 查詢字串和片段組件。
- 將 format 設為 ESM_FILE_FORMAT(resolved) 的結果。
- 否則:
- 將 format 設為 URL resolved 關聯的內容類型模組格式。
- 將 format 和 resolved 回傳至載入階段。
PACKAGE_RESOLVE(packageSpecifier, parentURL)
- 設 packageName 為 undefined。
- 若 packageSpecifier 為空字串,則:
- 拋出 Invalid Module Specifier 錯誤。
- 若 packageSpecifier 是 Node.js 內建模組名稱,則:
- 回傳字串 "node:" 連接 packageSpecifier 的結果。
- 若 packageSpecifier 不以 "@" 開頭,則:
- 將 packageName 設為 packageSpecifier 直到第一個 "/" 分隔符或字串結尾的子字串。
- 否則:
- 若 packageSpecifier 不包含 "/" 分隔符,則:
- 拋出 Invalid Module Specifier 錯誤。
- 將 packageName 設為 packageSpecifier 直到第二個 "/" 分隔符或字串結尾的子字串。
- 若 packageName 以 "." 開頭或包含 "\" 或 "%",則:
- 拋出 Invalid Module Specifier 錯誤。
- 設 packageSubpath 為 "." 連接 packageSpecifier 從 packageName 長度位置開始的子字串。
- 設 selfUrl 為 PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL) 的結果。
- 若 selfUrl 不為 undefined,則回傳 selfUrl。
- 當 parentURL 不是檔案系統根目錄時:
- 設 packageURL 為 "node_modules/" 連接 packageName,相對於 parentURL 的 URL 解析結果。
- 將 parentURL 設為 parentURL 的父目錄 URL。
- 若 packageURL 的目錄不存在,則:
- 繼續下一次迴圈迭代。
- 設 pjson 為 READ_PACKAGE_JSON(packageURL) 的結果。
- 若 pjson 不為 null 且 pjson.exports 不為 null 或 undefined,則:
- 回傳 PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions) 的結果。
- 否則,若 packageSubpath 等於 ".",則:
- 若 pjson.main 為字串,則:
- 回傳 packageURL 中 main 的 URL 解析結果。
- 否則:
- 回傳 packageURL 中 packageSubpath 的 URL 解析結果。
- 拋出 Module Not Found 錯誤。
PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL)
- 設 packageURL 為 LOOKUP_PACKAGE_SCOPE(parentURL) 的結果。
- 若 packageURL 為 null,則:
- 回傳 undefined。
- 設 pjson 為 READ_PACKAGE_JSON(packageURL) 的結果。
- 若 pjson 為 null 或 pjson.exports 為 null 或 undefined,則:
- 回傳 undefined。
- 若 pjson.name 等於 packageName,則:
- 回傳 PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions) 的結果。
- 否則回傳 undefined。
PACKAGE_EXPORTS_RESOLVE(packageURL, subpath, exports, conditions)
註:此函式由 CommonJS 解析演算法直接呼叫。
- 若 exports 是一個同時包含以 "." 開頭的鍵和不以 "." 開頭的鍵的物件,拋出 Invalid Package Configuration 錯誤。
- 若 subpath 等於 ".",則:
- 設 mainExport 為 undefined。
- 若 exports 為字串或陣列,或是未包含任何以 "." 開頭鍵的物件,則:
- 將 mainExport 設為 exports。
- 否則,若 exports 是一個包含 "." 屬性的物件,則:
- 將 mainExport 設為 exports["."]。
- 若 mainExport 不為 undefined,則:
- 設 resolved 為 PACKAGE_TARGET_RESOLVE( packageURL, mainExport, null, false, conditions) 的結果。
- 若 resolved 不為 null 或 undefined,回傳 resolved。
- 否則,若 exports 是一個物件且所有鍵皆以 "." 開頭,則:
- 斷言:subpath 以 "./" 開頭。
- 設 resolved 為 PACKAGE_IMPORTS_EXPORTS_RESOLVE( subpath, exports, packageURL, false, conditions) 的結果。
- 若 resolved 不為 null 或 undefined,回傳 resolved。
- 拋出 Package Path Not Exported 錯誤。
PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, conditions)
註:此函式由 CommonJS 解析演算法直接呼叫。
- 斷言:specifier 以 "#" 開頭。
- 若 specifier 精確等於 "#",則:
- 拋出 Invalid Module Specifier 錯誤。
- 設 packageURL 為 LOOKUP_PACKAGE_SCOPE(parentURL) 的結果。
- 若 packageURL 不為 null,則:
- 設 pjson 為 READ_PACKAGE_JSON(packageURL) 的結果。
- 若 pjson.imports 為非空物件,則:
- 設 resolved 為 PACKAGE_IMPORTS_EXPORTS_RESOLVE( specifier, pjson.imports, packageURL, true, conditions) 的結果。
- 若 resolved 不為 null 或 undefined,回傳 resolved。
- 拋出 Package Import Not Defined 錯誤。
PACKAGE_IMPORTS_EXPORTS_RESOLVE(matchKey, matchObj, packageURL, isImports, conditions)
- 若 matchKey 以 "/" 結尾,則:
- 拋出 Invalid Module Specifier 錯誤。
- 若 matchKey 是 matchObj 的鍵且不包含 "*",則:
- 設 target 為 matchObj[matchKey] 的值。
- 回傳 PACKAGE_TARGET_RESOLVE(packageURL, target, null, isImports, conditions) 的結果。
- 設 expansionKeys 為 matchObj 中僅包含單個 "*" 的鍵列表,按 PATTERN_KEY_COMPARE 函式排序(按特定性降序)。
- 對於 expansionKeys 中的每個鍵 expansionKey,執行:
- 設 patternBase 為 expansionKey 直到但排除第一個 "*" 字元的子字串。
- 若 matchKey 以 patternBase 開頭但不等於 patternBase,則:
- 設 patternTrailer 為 expansionKey 從第一個 "*" 字元之後的索引開始的子字串。
- 若 patternTrailer 長度為零,或 matchKey 以 patternTrailer 結尾且 matchKey 的長度大於或等於 expansionKey 的長度,則:
- 設 target 為 matchObj[expansionKey] 的值。
- 設 patternMatch 為 matchKey 從 patternBase 長度的索引開始,到 matchKey 長度減去 patternTrailer 長度的子字串。
- 回傳 PACKAGE_TARGET_RESOLVE(packageURL, target, patternMatch, isImports, conditions) 的結果。
- 回傳 null。
PATTERN_KEY_COMPARE(keyA, keyB)
- 斷言:keyA 僅包含一個 "*"。
- 斷言:keyB 僅包含一個 "*"。
- 設 baseLengthA 為 keyA 中 "*" 的索引。
- 設 baseLengthB 為 keyB 中 "*" 的索引。
- 若 baseLengthA 大於 baseLengthB,回傳 -1。
- 若 baseLengthB 大於 baseLengthA,回傳 1。
- 若 keyA 的長度大於 keyB 的長度,回傳 -1。
- 若 keyB 的長度大於 keyA 的長度,回傳 1。
- 回傳 0。
PACKAGE_TARGET_RESOLVE(packageURL, target, patternMatch, isImports, conditions)
- 若 target 是字串,則:
- 若 target 不以 "./" 開頭,則:
- 若 isImports 為 false,或 target 以 "../" 或 "/" 開頭,或 target 是有效的 URL,則:
- 拋出 Invalid Package Target 錯誤。
- 若 patternMatch 是字串,則:
- 回傳 PACKAGE_RESOLVE(target 中每個 "*" 實例皆替換為 patternMatch 的結果, packageURL + "/")。
- 回傳 PACKAGE_RESOLVE(target, packageURL + "/")。
- 若 target 以 "/" 或 "\" 分割後,在第一個 "." 區段後包含任何 ""、"."、".." 或 "node_modules" 區段(不區分大小寫,包含百分比編碼變體),拋出 Invalid Package Target 錯誤。
- 設 resolvedTarget 為 packageURL 和 target 連接的 URL 解析結果。
- 斷言:packageURL 包含於 resolvedTarget 中。
- 若 patternMatch 為 null,則:
- 回傳 resolvedTarget。
- 若 patternMatch 以 "/" 或 "\" 分割後包含任何 ""、"."、".." 或 "node_modules" 區段(不區分大小寫,包含百分比編碼變體),拋出 Invalid Module Specifier 錯誤。
- 回傳 resolvedTarget 中每個 "*" 實例皆替換為 patternMatch 的 URL 解析結果。
- 否則,若 target 是非空的物件,則:
- 若 target 包含任何 ECMA-262 6.1.7 陣列索引 定義的索引屬性鍵,拋出 Invalid Package Configuration 錯誤。
- 對於 target 的每個屬性 p(按物件插入順序):
- 若 p 等於 "default" 或 conditions 包含 p 的項目,則:
- 設 targetValue 為 target 中 p 屬性的值。
- 設 resolved 為 PACKAGE_TARGET_RESOLVE( packageURL, targetValue, patternMatch, isImports, conditions) 的結果。
- 若 resolved 等於 undefined,繼續迴圈。
- 回傳 resolved。
- 回傳 undefined。
- 否則,若 target 是陣列,則:
- 若 target.length 為零,回傳 null。
- 對於 target 中的每個項目 targetValue,執行:
- 設 resolved 為 PACKAGE_TARGET_RESOLVE( packageURL, targetValue, patternMatch, isImports, conditions) 的結果,若遇到任何 Invalid Package Target 錯誤,則繼續迴圈。
- 若 resolved 為 undefined,繼續迴圈。
- 回傳 resolved。
- 回傳或拋出最後的回退解析 null 回傳值或錯誤。
- 否則,若 target 為 null,回傳 null。
- 否則拋出 Invalid Package Target 錯誤。
ESM_FILE_FORMAT(url)
- 斷言:url 對應到一個存在的檔案。
- 若 url 以 ".mjs" 結尾,則:
- 回傳 "module"。
- 若 url 以 ".cjs" 結尾,則:
- 回傳 "commonjs"。
- 若 url 以 ".json" 結尾,則:
- 回傳 "json"。
- 若 url 以 ".wasm" 結尾,則:
- 回傳 "wasm"。
- 若
--experimental-addon-modules已啟用且 url 以 ".node" 結尾,則:
- 回傳 "addon"。
- 設 packageURL 為 LOOKUP_PACKAGE_SCOPE(url) 的結果。
- 設 pjson 為 READ_PACKAGE_JSON(packageURL) 的結果。
- 設 packageType 為 null。
- 若 pjson?.type 為 "module" 或 "commonjs",則:
- 將 packageType 設為 pjson.type。
- 若 url 以 ".js" 結尾,則:
- 若 packageType 不為 null,則:
- 回傳 packageType。
- 若 DETECT_MODULE_SYNTAX(source) 的結果為 true,則:
- 回傳 "module"。
- 回傳 "commonjs"。
- 若 url 沒有任何副檔名,則:
- 若 packageType 為 "module" 且 url 的檔案包含 WebAssembly 模組的 "application/wasm" 內容類型標頭,則:
- 回傳 "wasm"。
- 若 packageType 不為 null,則:
- 回傳 packageType。
- 若 DETECT_MODULE_SYNTAX(source) 的結果為 true,則:
- 回傳 "module"。
- 回傳 "commonjs"。
- 回傳 undefined (將在載入階段拋出錯誤)。
LOOKUP_PACKAGE_SCOPE(url)
- 設 scopeURL 為 url。
- 當 scopeURL 不是檔案系統根目錄時:
- 將 scopeURL 設為 scopeURL 的父 URL。
- 若 scopeURL 以 "node_modules" 路徑區段結尾,回傳 null。
- 設 pjsonURL 為 scopeURL 中 "package.json" 的解析結果。
- 若 pjsonURL 的檔案存在,則:
- 回傳 scopeURL。
- 回傳 null。
READ_PACKAGE_JSON(packageURL)
- 設 pjsonURL 為 packageURL 中 "package.json" 的解析結果。
- 若 pjsonURL 的檔案不存在,則:
- 回傳 null。
- 若 packageURL 的檔案無法解析為有效的 JSON,則:
- 拋出 Invalid Package Configuration 錯誤。
- 回傳 pjsonURL 檔案的已解析 JSON 來源。
DETECT_MODULE_SYNTAX(source)
- 將 source 解析為 ECMAScript 模組。
- 若解析成功,則:
- 若 source 包含頂層
await、靜態import或export陳述式,或import.meta,回傳 true。- 若 source 包含任何 CommonJS 封裝變數(
require、exports、module、__filename或__dirname)的頂層語彙宣告(const、let或class),回傳 true。- 回傳 false。
自訂 ESM 指定符解析演算法#
模組自訂掛鉤 提供了自訂 ESM 指定符解析演算法的機制。一個為 ESM 指定符提供 CommonJS 風格解析的範例是 commonjs-extension-resolution-loader。