Node.js v25.0.0 文件
- Node.js v25.0.0
- 目錄
-
索引
- 斷言測試
- 非同步上下文跟蹤
- 非同步鉤子
- 緩衝區
- C++ 外掛
- 使用 Node-API 的 C/C++ 外掛
- C++ 嵌入器 API
- 子程序
- 叢集
- 命令列選項
- 控制檯
- 加密
- 偵錯程式
- 已棄用的 API
- 診斷通道
- DNS
- 域
- 環境變數
- 錯誤
- 事件
- 檔案系統
- 全域性物件
- HTTP
- HTTP/2
- HTTPS
- 檢查器
- 國際化
- 模組:CommonJS 模組
- 模組:ECMAScript 模組
- 模組:
node:moduleAPI - 模組:包
- 模組:TypeScript
- 網路
- 作業系統
- 路徑
- 效能鉤子
- 許可權
- 程序
- Punycode
- 查詢字串
- 逐行讀取
- REPL
- 報告
- 單一可執行檔案應用
- SQLite
- 流
- 字串解碼器
- 測試執行器
- 定時器
- TLS/SSL
- 跟蹤事件
- TTY
- UDP/資料報
- URL
- 實用工具
- V8
- 虛擬機器
- WASI
- Web Crypto API
- Web Streams API
- 工作執行緒
- Zlib
- 其他版本
- 選項
模組:ECMAScript 模組#
簡介#
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 中 "type" 欄位值為 "module",或 --input-type 標誌值為 "module" 來告訴 Node.js 將 JavaScript 解釋為 ES 模組。這些都是程式碼旨在作為 ES 模組執行的明確標記。
相反,開發者也可以透過 .cjs 副檔名、package.json 中 "type" 欄位值為 "commonjs",或 --input-type 標誌值為 "commonjs" 來明確告訴 Node.js 將 JavaScript 解釋為 CommonJS。
當代碼缺少任何一種模組系統的明確標記時,Node.js 將檢查模組的原始碼以尋找 ES 模組語法。如果找到此類語法,Node.js 將作為 ES 模組執行程式碼;否則它將作為 CommonJS 執行模組。更多詳情請參閱確定模組系統。
包#
此部分已移至模組:包。
import 說明符#
術語#
import 語句的*說明符*是 from 關鍵字後面的字串,例如 import { sep } from 'node:path' 中的 'node:path'。說明符也用於 export from 語句,以及作為 import() 表示式的引數。
說明符有三種類型:
-
相對說明符,如
'./startup.js'或'../config.mjs'。它們指向相對於匯入檔案位置的路徑。對於這些說明符,副檔名總是必需的。 -
裸說明符,如
'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 在瀏覽器環境中的行為一致,假設伺服器配置典型。
URL#
ES 模組以 URL 的形式進行解析和快取。這意味著特殊字元必須進行百分號編碼,例如 # 編碼為 %23,? 編碼為 %3F。
支援 file:、node: 和 data: URL 方案。像 'https://example.com/app.js' 這樣的說明符在 Node.js 中本身不受支援,除非使用自定義 HTTPS 載入器。
file: URL#
如果用於解析模組的 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: 匯入#
支援使用data: URL匯入以下 MIME 型別:
text/javascript用於 ES 模組application/json用於 JSONapplication/wasm用於 Wasm
import 'data:text/javascript,console.log("hello!");';
import _ from 'data:application/json,"world!"' with { type: 'json' };
data: URL 只解析內建模組的裸說明符和絕對說明符。解析相對說明符不起作用,因為 data: 不是一個特殊方案。例如,嘗試從 data:text/javascript,import "./foo"; 載入 ./foo 會因無法解析而失敗,因為 data: URL 沒有相對解析的概念。
node: 匯入#
支援 node: URL 作為載入 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 的命名匯出。還提供了一個預設匯出,其值為 CommonJS 的 exports。預設匯出可用於修改命名匯出等操作。內建模組的命名匯出僅透過呼叫 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;
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#
- 型別:<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)#
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 模組中使用,但動態 import() 表示式在 CommonJS 中也受支援,用於載入 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
這個模組名稱空間奇異物件可以在使用 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 模組的 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'
// }
從最後一個被記錄的模組名稱空間奇異物件的例子可以看出,當模組被匯入時,name 匯出是從 module.exports 物件複製過來並直接設定在 ES 模組名稱空間上的。
對於這些命名匯出,不會檢測到即時繫結的更新或新增到 module.exports 的新匯出。
命名匯出的檢測基於常見的語法模式,但並不總能正確檢測到命名匯出。在這些情況下,使用上述的預設匯入形式可能是更好的選擇。
命名匯出檢測涵蓋了許多常見的匯出模式、再匯出模式以及構建工具和轉譯器的輸出。有關所實現的具體語義,請參閱 cjs-module-lexer。
ES 模組與 CommonJS 之間的差異#
沒有 require、exports 或 module.exports#
在大多數情況下,可以使用 ES 模組的 import 來載入 CommonJS 模組。
如果需要,可以在 ES 模組中使用 module.createRequire() 構建一個 require 函式。
沒有 __filename 或 __dirname#
這些 CommonJS 變數在 ES 模組中不可用。
__filename 和 __dirname 的用例可以透過 import.meta.filename 和 import.meta.dirname 來實現。
沒有 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 使用。模組自定義鉤子可以提供替代方案。
JSON 模組#
JSON 檔案可以透過 import 引用:
import packageConfig from './package.json' with { type: 'json' };
with { type: 'json' } 語法是強制性的;請參閱匯入屬性。
匯入的 JSON 僅公開一個 default 匯出。不支援命名匯出。為了避免重複,會在 CommonJS 快取中建立一個快取條目。如果該 JSON 模組已經從相同路徑匯入過,CommonJS 會返回相同的物件。
Wasm 模組#
支援匯入 WebAssembly 模組例項和 WebAssembly 源階段匯入。
這兩種整合都符合WebAssembly 的 ES 模組整合提案。
Wasm 源階段匯入#
源階段匯入提案允許使用 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 字串內建函式#
在匯入 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.compile API 重新編譯模組並停用字串內建函式,否則無法透過 WebAssembly.Module.imports(mod) 檢查或虛擬化。
在模組例項化之前以源階段匯入模組,也會自動使用編譯時內建函式:
import source mod from './string-len.wasm';
const { exports: { getLength } } = await WebAssembly.instantiate(mod, {});
getLength('foo'); // Also returns 3.
Wasm 例項階段匯入#
例項匯入允許任何 .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`
});
載入器#
之前的載入器文件現在位於模組:自定義鉤子。
解析和載入演算法#
特性#
預設解析器具有以下屬性:
- 基於 FileURL 的解析,與 ES 模組使用的方式相同
- 相對和絕對 URL 解析
- 無預設副檔名
- 無資料夾主檔案
- 透過 node_modules 查詢裸說明符包
- 對未知副檔名或協議不會失敗
- 可以可選地向載入階段提供格式提示
預設載入器具有以下屬性:
- 透過
node:URL 支援內建模組載入 - 透過
data:URL 支援“內聯”模組載入 - 支援
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"]。
解析器可能丟擲以下錯誤:
- 無效的模組說明符:模組說明符是無效的 URL、包名或包子路徑說明符。
- 無效的包配置:package.json 配置無效或包含無效配置。
- 無效的包目標:包的 exports 或 imports 為包定義了一個無效型別或字串的目標模組。
- 包路徑未匯出:包的 exports 沒有為給定模組定義或允許包中的目標子路徑。
- 包匯入未定義:包的 imports 沒有定義該說明符。
- 未找到模組:請求的包或模組不存在。
- 不支援的目錄匯入:解析的路徑對應一個目錄,這不是模組匯入支援的目標。
解析演算法規範#
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"),則
- 丟擲“無效的模組說明符”錯誤。
- 如果位於 resolved 的檔案是一個目錄,則
- 丟擲“不支援的目錄匯入”錯誤。
- 如果位於 resolved 的檔案不存在,則
- 丟擲“未找到模組”錯誤。
- 將 resolved 設定為 resolved 的真實路徑,並保持相同的 URL 查詢字串和片段元件。
- 將 format 設定為 ESM_FILE_FORMAT(resolved) 的結果。
- 否則,
- 將 format 設定為與 URL resolved 關聯的內容型別的模組格式。
- 將 format 和 resolved 返回給載入階段。
PACKAGE_RESOLVE(packageSpecifier, parentURL)
- 令 packageName 為 undefined。
- 如果 packageSpecifier 是一個空字串,則
- 丟擲“無效的模組說明符”錯誤。
- 如果 packageSpecifier 是一個 Node.js 內建模組名,則
- 返回字串 "node:" 與 packageSpecifier 的拼接結果。
- 如果 packageSpecifier 不以 "@" 開頭,則
- 將 packageName 設定為 packageSpecifier 直到第一個 "/" 分隔符或字串末尾的子串。
- 否則,
- 如果 packageSpecifier 不包含 "/" 分隔符,則
- 丟擲“無效的模組說明符”錯誤。
- 將 packageName 設定為 packageSpecifier 直到第二個 "/" 分隔符或字串末尾的子串。
- 如果 packageName 以 "." 開頭或包含 "\" 或 "%",則
- 丟擲“無效的模組說明符”錯誤。
- 令 packageSubpath 為 "." 與從 packageName 長度位置開始的 packageSpecifier 子串的拼接結果。
- 令 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 是一個字串,則
- 返回 main 在 packageURL 中的 URL 解析結果。
- 否則,
- 返回 packageSubpath 在 packageURL 中的 URL 解析結果。
- 丟擲“未找到模組”錯誤。
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 是一個同時包含以 "." 開頭的鍵和不以 "." 開頭的鍵的物件,則丟擲“無效的包配置”錯誤。
- 如果 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 是一個物件且 exports 的所有鍵都以 "." 開頭,則
- 斷言:subpath 以 "./" 開頭。
- 令 resolved 為 PACKAGE_IMPORTS_EXPORTS_RESOLVE( subpath, exports, packageURL, false, conditions) 的結果。
- 如果 resolved 不為 null 或 undefined,則返回 resolved。
- 丟擲“包路徑未匯出”錯誤。
PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, conditions)
注意:此函式由 CommonJS 解析演算法直接呼叫。
- 斷言:specifier以"#"開頭。
- 如果 specifier 完全等於 "#" 或以 "#/" 開頭,則
- 丟擲“無效的模組說明符”錯誤。
- 令 packageURL 為 LOOKUP_PACKAGE_SCOPE(parentURL) 的結果。
- 如果 packageURL 不為 null,則
- 令 pjson 為 READ_PACKAGE_JSON(packageURL) 的結果。
- 如果 pjson.imports 是一個非 null 物件,則
- 令 resolved 為 PACKAGE_IMPORTS_EXPORTS_RESOLVE( specifier, pjson.imports, packageURL, true, conditions) 的結果。
- 如果 resolved 不為 null 或 undefined,則返回 resolved。
- 丟擲“包匯入未定義”錯誤。
PACKAGE_IMPORTS_EXPORTS_RESOLVE(matchKey, matchObj, packageURL, isImports, conditions)
- 如果 matchKey 以 "/" 結尾,則
- 丟擲“無效的模組說明符”錯誤。
- 如果 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,則
- 丟擲“無效的包目標”錯誤。
- 如果 patternMatch 是一個字串,則
- 返回 PACKAGE_RESOLVE(將 target 中每個 "*" 替換為 patternMatch 的結果, packageURL + "/")。
- 返回 PACKAGE_RESOLVE(target, packageURL + "/")。
- 如果 target 以 "/" 或 "\" 分割後,在第一個 "." 段之後包含任何 ""、"."、".." 或 "node_modules" 段(不區分大小寫,包括百分號編碼的變體),則丟擲“無效的包目標”錯誤。
- 令 resolvedTarget 為 packageURL 和 target 拼接後的 URL 解析結果。
- 斷言:resolvedTarget 包含 packageURL。
- 如果 patternMatch 為 null,則
- 返回 resolvedTarget。
- 如果 patternMatch 以 "/" 或 "\" 分割後包含任何 ""、"."、".." 或 "node_modules" 段(不區分大小寫,包括百分號編碼的變體),則丟擲“無效的模組說明符”錯誤。
- 返回將 resolvedTarget 中每個 "*" 替換為 patternMatch 後的 URL 解析結果。
- 否則,如果 target 是一個非 null 物件,則
- 如果 target 包含任何索引屬性鍵(如 ECMA-262 6.1.7 陣列索引 中定義),則丟擲“無效的包配置”錯誤。
- 對於 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) 的結果,如果遇到任何“無效的包目標”錯誤則繼續迴圈。
- 如果 resolved 為 undefined,則繼續迴圈。
- 返回 resolved。
- 返回或丟擲最後一個後備解析的 null 返回值或錯誤。
- 否則,如果 target 為 null,則返回 null。
- 否則丟擲“無效的包目標”錯誤。
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 為 "package.json" 在 scopeURL 內的解析結果。
- 如果 pjsonURL 處的檔案存在,則
- 返回 scopeURL。
- 返回 null。
READ_PACKAGE_JSON(packageURL)
- 令 pjsonURL 為 "package.json" 在 packageURL 中的解析結果。
- 如果 pjsonURL 處的檔案不存在,則
- 返回 null。
- 如果 packageURL 處的檔案無法解析為有效的 JSON,則
- 丟擲“無效的包配置”錯誤。
- 返回位於 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。