模組:ECMAScript 模組#

穩定性:2 - 穩定

簡介#

ECMAScript 模組是 官方標準格式,用於封裝 JavaScript 程式碼以供重複使用。模組使用各種 importexport 陳述式來定義。

以下 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")或 --experimental-default-type 旗標(值為 "module")來告知 Node.js 將 JavaScript 解釋為 ES 模組。這些是明確標記,表示程式碼打算以 ES 模組執行。

相反地,作者可以透過 .cjs 檔案副檔名、package.json "type" 欄位(值為 "commonjs")、--input-type 旗標(值為 "commonjs")或 --experimental-default-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 架構獲得支援。在 Node.js 中,除非使用 自訂 HTTPS 載入器,否則原生不支援 'https://example.com/app.js' 之類的指定符。

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 類型進行匯入

  • ES 模組的 text/javascript
  • JSON 的 application/json
  • Wasm 的 application/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'; 

匯入屬性#

穩定性:1.1 - 積極開發

此功能先前稱為「匯入斷言」,並使用 assert 關鍵字,而非 with。程式碼中任何使用先前 assert 關鍵字的地方都應更新為使用 with

匯入屬性提案 為模組匯入陳述式新增內嵌語法,以便傳遞模組指定符號之外的更多資訊。

import fooData from './foo.json' with { type: 'json' };

const { default: barData } =
  await import('./bar.json', { with: { type: 'json' } }); 

Node.js 支援下列 type 值,屬性對其為強制性的

屬性 type需要用於
'json'JSON 模組

內建模組#

核心模組 提供其公開 API 的命名匯出。還提供預設匯出,即 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; 

import() 表達式#

動態 import() 在 CommonJS 和 ES 模組中都獲得支援。在 CommonJS 模組中,它可用於載入 ES 模組。

import.meta#

import.meta meta 屬性是一個包含下列屬性的 物件

import.meta.dirname#

穩定性:1.2 - 發行候選版本

注意事項:僅存在於 file: 模組中。

import.meta.filename#

穩定性:1.2 - 發行候選版本

注意事項 只有本機模組支援此屬性。未使用 file: 協定的模組不會提供此屬性。

import.meta.url#

此處的定義與瀏覽器中提供目前模組檔案的 URL 完全相同。

這啟用了有用的模式,例如相對檔案載入

import { readFileSync } from 'node:fs';
const buffer = readFileSync(new URL('./data.proto', import.meta.url)); 

import.meta.resolve(specifier)#

穩定性:1.2 - 發行候選版本

  • specifier <string> 相對於目前模組要解析的模組識別碼。
  • 傳回:<string> 識別碼會解析到的絕對 URL 字串。

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 旗標時,該函式會接受第二個參數

  • parent <string> | <URL> 要從中解析的選用絕對父模組 URL。預設:import.meta.url

與 CommonJS 的互通性#

import 陳述式#

import 陳述式可以參照 ES 模組或 CommonJS 模組。import 陳述式僅允許在 ES 模組中使用,但動態 import() 表達式在 CommonJS 中受支援,用於載入 ES 模組。

匯入 CommonJS 模組 時,module.exports 物件會提供為預設匯出。命名匯出可能會提供,由靜態分析提供,以方便更佳的生態系統相容性。

require#

CommonJS 模組 require 始終將其引用的檔案視為 CommonJS。

不支援使用 require 載入 ES 模組,因為 ES 模組具有非同步執行。請改用 import() 從 CommonJS 模組載入 ES 模組。

CommonJS 名稱空間#

CommonJS 模組包含一個 module.exports 物件,其類型可以是任何類型。

匯入 CommonJS 模組時,可以使用 ES 模組預設匯入或其對應的簡易語法可靠地匯入

import { default as cjs } from 'cjs';

// The following import statement is "syntax sugar" (equivalent but sweeter)
// for `{ default as cjsSugar }` in the above import statement:
import cjsSugar from 'cjs';

console.log(cjs);
console.log(cjs === cjsSugar);
// Prints:
//   <module.exports>
//   true 

CommonJS 模組的 ECMAScript 模組名稱空間表示形式永遠是名稱空間,其中 default 匯出金鑰指向 CommonJS module.exports 值。

這個模組名稱空間 Exotic 物件可以在使用 import * as m from 'cjs' 或動態匯入時直接觀察到

import * as m from 'cjs';
console.log(m);
console.log(m === await import('cjs'));
// Prints:
//   [Module] { default: <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' }, name: 'exported' } 

從記錄的模組名稱空間 Exotic 物件的最後一個範例中可以看到,name 匯出會從 module.exports 物件複製,並在匯入模組時直接設定在 ES 模組名稱空間上。

這些指定匯出不會偵測到對 module.exports 的即時繫結更新或新增匯出。

指定匯出的偵測是根據常見的語法模式,但並非總是能正確偵測到指定匯出。在這些情況下,使用上面描述的預設匯入形式會是更好的選擇。

指定匯出偵測涵蓋許多常見的匯出模式、重新匯出模式和建置工具及轉譯器的輸出。請參閱 cjs-module-lexer 以了解實作的確切語意。

ES 模組和 CommonJS 之間的差異#

沒有 requireexportsmodule.exports#

在大部分情況下,ES 模組的 import 可用於載入 CommonJS 模組。

如果需要,可以使用 module.createRequire() 在 ES 模組中建構一個 require 函式。

沒有 __filename__dirname#

這些 CommonJS 變數在 ES 模組中不可用。

__filename__dirname 的使用案例可透過 import.meta.filenameimport.meta.dirname 複製。

沒有 Addon 載入#

Addon 目前不支援 ES 模組載入。

它們可以用 module.createRequire()process.dlopen 載入。

沒有 require.resolve#

相對解析可透過 new URL('./local', import.meta.url) 處理。

對於完整的 require.resolve 替換,有 import.meta.resolve API。

或者可以使用 module.createRequire()

沒有 NODE_PATH#

NODE_PATH 不是解析 import 規範的一部分。如果需要此行為,請使用符號連結。

沒有 require.extensions#

import 不使用 require.extensions。模組自訂掛勾可以提供替代方案。

沒有 require.cache#

import 不使用 require.cache,因為 ES 模組載入器有自己的獨立快取。

JSON 模組#

穩定性:1 - 實驗性

import 可以參照 JSON 檔案

import packageConfig from './package.json' with { type: 'json' }; 

with { type: 'json' } 語法是強制性的;請參閱 Import 屬性

匯入的 JSON 僅公開 default 匯出。不支援命名匯出。在 CommonJS 快取中建立快取條目以避免重複。如果 JSON 模組已從同一路徑匯入,則在 CommonJS 中會傳回同一個物件。

Wasm 模組#

穩定性:1 - 實驗性

--experimental-wasm-modules 旗標下支援匯入 WebAssembly 模組,允許將任何 .wasm 檔案作為一般模組匯入,同時也支援其模組匯入。

此整合符合 WebAssembly 的 ES 模組整合建議

例如,包含下列內容的 index.mjs

import * as M from './module.wasm';
console.log(M); 

在下列情況下執行

node --experimental-wasm-modules index.mjs 

會提供 module.wasm 實例化的匯出介面。

頂層 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`
}); 

HTTPS 和 HTTP 匯入#

穩定性:1 - 實驗性

--experimental-network-imports 旗標下,支援使用 https:http: 匯入基於網路的模組。這允許類似於網路瀏覽器的匯入在 Node.js 中運作,但由於在特權環境中執行與在瀏覽器沙盒中執行時不同的應用程式穩定性和安全性考量,因此有一些差異。

匯入僅限於 HTTP/1#

尚未支援 HTTP/2 和 HTTP/3 的自動協定協商。

HTTP 僅限於迴圈介面地址#

http: 容易受到中間人攻擊,且不允許用於 IPv4 地址 127.0.0.0/8 (127.0.0.1127.255.255.255) 和 IPv6 地址 ::1 以外的地址。http: 的支援旨在用於本地開發。

驗證資訊絕不會傳送至目的地伺服器。#

AuthorizationCookieProxy-Authorization 標頭不會傳送至伺服器。請避免在匯入 URL 的部分中包含使用者資訊。目前正在制定一個安全模型,以安全地在伺服器上使用這些標頭。

CORS 永遠不會在目的地伺服器上檢查#

CORS 設計為允許伺服器將 API 的使用者限制在特定主機組。這不受支援,因為這對基於伺服器的實作沒有意義。

無法載入非網路相依性#

這些模組無法存取不在 http:https: 上的其他模組。若要避免安全性問題,但仍存取本機模組,請傳入本機相依性的參考。

// file.mjs
import worker_threads from 'node:worker_threads';
import { configure, resize } from 'https://example.com/imagelib.mjs';
configure({ worker_threads }); 
// https://example.com/imagelib.mjs
let worker_threads;
export function configure(opts) {
  worker_threads = opts.worker_threads;
}
export function resize(img, size) {
  // Perform resizing in worker_thread to avoid main thread blocking
} 

預設未啟用基於網路的載入#

目前需要 --experimental-network-imports 旗標才能透過 http:https: 載入資源。未來將使用不同的機制來強制執行這項規定。需要選擇加入才能防止傳遞相依性不經意地使用可能會影響 Node.js 應用程式可靠性的可變動狀態。

載入器#

以前的載入器文件現在位於 模組:自訂掛勾

解析和載入演算法#

功能#

預設解析器具有下列屬性

  • ES 模組使用的基於 FileURL 的解析
  • 相對和絕對 URL 解析
  • 沒有預設擴充功能
  • 沒有資料夾主程式
  • 透過 node_modules 進行裸露規格套件解析尋找
  • 未知擴充功能或通訊協定不會失敗
  • 可以選擇在載入階段提供格式提示

預設載入器具有下列屬性

  • 透過 node: URL 支援內建模組載入
  • 透過 data: URL 支援「內嵌」模組載入
  • 支援 file: 模組載入
  • 其他任何 URL 通訊協定都會失敗
  • file: 載入時,未知擴充功能會失敗(僅支援 .cjs.js.mjs

解析演算法#

載入 ES 模組規格的演算法透過下列 ESM_RESOLVE 方法提供。它會傳回相對於 parentURL 的模組規格已解析的 URL。

解析演算法會決定模組載入的完整已解析 URL,以及其建議的模組格式。解析演算法不會決定已解析 URL 通訊協定是否可以載入,或是否允許檔案擴充功能,而是由 Node.js 在載入階段套用這些驗證(例如,如果要求載入的 URL 具有非 file:data:node: 的通訊協定,或已啟用 --experimental-network-imports,則為 https:)。

演算法也會嘗試根據擴充功能來決定檔案格式(請參閱下列 ESM_FILE_FORMAT 演算法)。如果它無法辨識檔案擴充功能(例如,如果不是 .mjs.cjs.json),則會傳回 undefined 格式,這會在載入階段引發例外狀況。

決定已解析 URL 模組格式的演算法由 ESM_FILE_FORMAT 提供,它會傳回任何檔案的唯一模組格式。ECMAScript 模組會傳回 「模組」格式,而 「commonjs」 格式用於表示透過傳統 CommonJS 載入器進行載入。其他格式(例如 「addon」)可以在未來的更新中擴充。

在以下演算法中,除非另有說明,否則所有子常式錯誤都會傳播為這些頂層常式的錯誤。

defaultConditions 是條件環境名稱陣列,["node", "import"]

解析器可能會擲出下列錯誤

  • 無效模組規格:模組規格是無效的 URL、套件名稱或套件子路徑規格。
  • 無效套件組態:package.json 組態無效或包含無效組態。
  • 無效套件目標:套件匯出或匯入定義套件的目標模組,而該目標模組為無效類型或字串目標。
  • 套件路徑未匯出:套件匯出未定義或不允許套件中給定模組的目標子路徑。
  • 套件匯入未定義:套件匯入未定義規格。
  • 找不到模組:請求的套件或模組不存在。
  • 不支援目錄匯入:已解析的路徑對應至目錄,而目錄並非模組匯入的支援目標。

解析演算法規範#

ESM_RESOLVE(specifier, parentURL)

  1. resolved未定義
  2. 如果 specifier 是有效的 URL,則
    1. resolved 設為將 specifier 解析並重新序列化為 URL 的結果。
  3. 否則,如果 specifier"/""./""../" 開頭,則
    1. resolved 設為 specifier 相對於 parentURL 的 URL 解析結果。
  4. 否則,如果 specifier"#" 開頭,則
    1. resolved 設為 PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, defaultConditions) 的結果。
  5. 否則,
    1. 注意:specifier 現在是一個裸 specifier。
    2. 設定 resolvedPACKAGE_RESOLVE(specifier, parentURL) 的結果。
  6. formatundefined
  7. 如果 resolved"file:" URL,則
    1. 如果 resolved 包含任何 "/""\" 的百分比編碼(分別為 "%2F""%5C"),則
      1. 擲出 Invalid Module Specifier 錯誤。
    2. 如果 resolved 的檔案是一個目錄,則
      1. 擲出 Unsupported Directory Import 錯誤。
    3. 如果 resolved 的檔案不存在,則
      1. 擲出 Module Not Found 錯誤。
    4. 設定 resolvedresolved 的真實路徑,並維持相同的 URL 查詢字串和片段組件。
    5. 設定 formatESM_FILE_FORMAT(resolved) 的結果。
  8. 否則,
    1. 設定 format 為與 URL resolved 相關的內容類型的模組格式。
  9. 傳回 formatresolved 至載入階段

PACKAGE_RESOLVE(packageSpecifier, parentURL)

  1. packageNameundefined
  2. 如果 packageSpecifier 是空字串,則
    1. 擲出 Invalid Module Specifier 錯誤。
  3. 如果 packageSpecifier 是 Node.js 內建模組名稱,則
    1. 傳回字串 "node:" 連接 packageSpecifier
  4. 如果 packageSpecifier 不是以 "@" 開頭,則
    1. 設定 packageNamepackageSpecifier 的子字串,直到第一個 "/" 分隔符號或字串結尾。
  5. 否則,
    1. 如果 packageSpecifier 不包含 "/" 分隔符號,則
      1. 擲出 Invalid Module Specifier 錯誤。
    2. 設定 packageNamepackageSpecifier 的子字串,直到第二個 "/" 分隔符號或字串結尾。
  6. 如果 packageName"." 開頭或包含 "\""%",則
    1. 擲出 Invalid Module Specifier 錯誤。
  7. packageSubpath"."packageSpecifier 的子字串相連,從 packageName 長度的位置開始。
  8. 如果 packageSubpath"/" 結尾,則
    1. 擲出 Invalid Module Specifier 錯誤。
  9. selfUrlPACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL) 的結果。
  10. 如果 selfUrl 不是 undefined,傳回 selfUrl
  11. parentURL 不是檔案系統根目錄時,
    1. packageURL"node_modules/"packageSpecifier 相連的 URL 解析,相對於 parentURL
    2. parentURL 設為 parentURL 的父資料夾 URL。
    3. 如果 packageURL 中的資料夾不存在,則
      1. 繼續下一個迴圈迭代。
    4. pjsonREAD_PACKAGE_JSON(packageURL) 的結果。
    5. 如果 pjson 不是 nullpjson.exports 不是 nullundefined,則
      1. 傳回 PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions) 的結果。
    6. 否則,如果 packageSubpath 等於 ".",則
      1. 如果 pjson.main 是字串,則
        1. 傳回 packageURLmain 的 URL 解析。
    7. 否則,
      1. 傳回 packageURLpackageSubpath 的 URL 解析。
  12. 擲出 Module Not Found 錯誤。

PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL)

  1. packageURLLOOKUP_PACKAGE_SCOPE(parentURL) 的結果。
  2. 如果 packageURLnull,則
    1. 傳回 undefined
  3. pjsonREAD_PACKAGE_JSON(packageURL) 的結果。
  4. 如果 pjsonnull 或如果 pjson.exportsnullundefined,則
    1. 傳回 undefined
  5. 如果 pjson.name 等於 packageName,則
    1. 傳回 PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions) 的結果。
  6. 否則,傳回 undefined

PACKAGE_EXPORTS_RESOLVE(packageURL, subpath, exports, conditions)

  1. 如果 exports 是同時具有以 "." 開頭的鍵和不以 "." 開頭的鍵的物件,則擲出 無效的套件組態 錯誤。
  2. 如果 subpath 等於 ".",則
    1. mainExport未定義
    2. 如果 exports 是字串或陣列,或是不包含任何以 "." 開頭的鍵的物件,則
      1. mainExport 設為 exports
    3. 否則,如果 exports 是包含 "." 屬性的物件,則
      1. mainExport 設為 exports["."]。
    4. 如果 mainExport 不為 未定義,則
      1. resolvedPACKAGE_TARGET_RESOLVE( packageURL, mainExport, null, false, conditions) 的結果。
      2. 如果 resolved 不為 null未定義,則傳回 resolved
  3. 否則,如果 exports 是物件且 exports 的所有鍵都以 "." 開頭,則
    1. 斷言:subpath"./" 開頭。
    2. resolvedPACKAGE_IMPORTS_EXPORTS_RESOLVE( subpath, exports, packageURL, false, conditions) 的結果。
    3. 如果 resolved 不為 null未定義,則傳回 resolved
  4. 擲出 套件路徑未匯出 錯誤。

PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, conditions)

  1. 斷言:specifier"#" 開頭。
  2. 如果 specifier 完全等於 "#" 或以 "#/" 開頭,則
    1. 擲出 Invalid Module Specifier 錯誤。
  3. packageURLLOOKUP_PACKAGE_SCOPE(parentURL) 的結果。
  4. 如果 packageURL 不為 null,則
    1. pjsonREAD_PACKAGE_JSON(packageURL) 的結果。
    2. 如果 pjson.imports 是非 null 物件,則
      1. resolvedPACKAGE_IMPORTS_EXPORTS_RESOLVE( specifier, pjson.imports, packageURL, true, conditions) 的結果。
      2. 如果 resolved 不為 null未定義,則傳回 resolved
  5. 擲出 套件匯入未定義 錯誤。

PACKAGE_IMPORTS_EXPORTS_RESOLVE(matchKey, matchObj, packageURL, isImports, conditions)

  1. 如果 matchKeymatchObj 的鍵且不包含 "*",則
    1. targetmatchObj[matchKey] 的值。
    2. 傳回 PACKAGE_TARGET_RESOLVE(packageURL, target, null, isImports, conditions) 的結果。
  2. expansionKeys 成為 matchObj 中只包含單一 "*" 的鍵清單,依據 PATTERN_KEY_COMPARE 排序函數排序,其以遞減的特定性順序排序。
  3. 對於 expansionKeys 中的每個鍵 expansionKey,執行下列動作
    1. patternBase 成為 expansionKey 的子字串,直到但排除第一個 "*" 字元。
    2. 如果 matchKeypatternBase 開頭但不等於 patternBase,則
      1. patternTrailer 成為 expansionKey 中從第一個 "*" 字元後的索引子字串。
      2. 如果 patternTrailer 的長度為零,或如果 matchKeypatternTrailer 結尾且 matchKey 的長度大於或等於 expansionKey 的長度,則
        1. target 成為 matchObj[expansionKey] 的值。
        2. patternMatch 成為 matchKey 的子字串,從 patternBase 長度的索引開始,直到 matchKey 的長度減去 patternTrailer 的長度。
        3. 傳回 PACKAGE_TARGET_RESOLVE(packageURL, target, patternMatch, isImports, conditions) 的結果。
  4. 傳回 null

PATTERN_KEY_COMPARE(keyA, keyB)

  1. 斷言:keyA"/" 結尾或只包含單一 "*"
  2. 斷言:keyB"/" 結尾或只包含單一 "*"
  3. 如果 keyA 包含 "*",則讓 baseLengthAkeyA"*" 的索引加一,否則為 keyA 的長度。
  4. 如果 keyB 包含 "*",則讓 baseLengthBkeyB"*" 的索引加一,否則為 keyB 的長度。
  5. 如果 baseLengthA 大於 baseLengthB,傳回 -1。
  6. 如果 baseLengthB 大於 baseLengthA,傳回 1。
  7. 如果 keyA 不包含 "*",傳回 1。
  8. 如果 keyB 不包含 "*",傳回 -1。
  9. 如果 keyA 的長度大於 keyB 的長度,傳回 -1。
  10. 如果 keyB 的長度大於 keyA 的長度,傳回 1。
  11. 傳回 0。

PACKAGE_TARGET_RESOLVE(packageURL, target, patternMatch, isImports, conditions)

  1. 如果 target 是字串,則
    1. 如果 target 沒有以 "./" 開頭,則
      1. 如果 isImportsfalse,或如果 target"../""/" 開頭,或如果 target 是有效的 URL,則
        1. 擲回 無效套件目標 錯誤。
      2. 如果 patternMatch 是字串,則
        1. 傳回 PACKAGE_RESOLVE(將 target 中的每個 "*" 執行個體替換為 patternMatchpackageURL + "/")。
      3. 傳回 PACKAGE_RESOLVE(targetpackageURL + "/")。
    2. 如果以 "/""\" 分割的 target 包含任何 """.""..""node_modules" 片段,不分大小寫且包含百分比編碼變體,則擲回 無效套件目標 錯誤。
    3. resolvedTargetpackageURLtarget 連接的 URL 解析。
    4. 斷言:packageURL 包含在 resolvedTarget 中。
    5. 如果 patternMatchnull,則
      1. 傳回 resolvedTarget
    6. 如果以 "/""\" 分割的 patternMatch 包含任何 """.""..""node_modules" 片段,不分大小寫且包含百分比編碼變體,則擲回 無效模組指定項 錯誤。
    7. 傳回將 resolvedTarget 中的每個 "*" 執行個體替換為 patternMatch 的 URL 解析。
  2. 否則,如果 target 是非空物件,則
    1. 如果 target 包含任何索引屬性鍵,如 ECMA-262 6.1.7 陣列索引 中所定義,則擲回 無效套件組態 錯誤。
    2. 對於 target 的每個屬性 p,依物件插入順序,
      1. 如果 p 等於 "default"conditions 包含 p 的項目,則
        1. targetValue 成為 targetp 屬性的值。
        2. resolved 成為 PACKAGE_TARGET_RESOLVE( packageURL, targetValue, patternMatch, isImports, conditions) 的結果。
        3. 如果 resolved 等於 undefined,則繼續迴圈。
        4. 傳回 resolved
    3. 傳回 undefined
  3. 否則,如果 target 是陣列,則
    1. 如果 _target.length 為零,則傳回 null
    2. 對於 target 中的每個項目 targetValue,執行
      1. resolved 成為 PACKAGE_TARGET_RESOLVE( packageURL, targetValue, patternMatch, isImports, conditions) 的結果,繼續迴圈處理任何 無效套件目標 錯誤。
      2. 如果 resolvedundefined,則繼續迴圈。
      3. 傳回 resolved
    3. 傳回或擲回最後的備援解析 null 傳回或錯誤。
  4. 否則,如果 targetnull,則傳回 null
  5. 否則擲回 無效套件目標 錯誤。

ESM_FILE_FORMAT(url)

  1. 斷言:url 對應到現有檔案。
  2. 如果 url".mjs" 結尾,則
    1. 傳回 "module"
  3. 如果 url".cjs" 結尾,則
    1. 傳回 "commonjs"
  4. 如果 url".json" 結尾,則
    1. 傳回 "json"
  5. 如果已啟用 --experimental-wasm-modulesurl".wasm" 結尾,則
    1. 傳回 "wasm"
  6. packageURL 成為 LOOKUP_PACKAGE_SCOPE(url) 的結果。
  7. pjsonREAD_PACKAGE_JSON(packageURL) 的結果。
  8. packageType 成為 null
  9. 如果 pjson?.type"module""commonjs",則
    1. packageType 設定為 pjson.type
  10. 如果 url".js" 結尾,則
    1. 如果 packageType 不是 null,則
      1. 傳回 packageType
    2. 如果啟用 --experimental-detect-module 且模組的來源包含靜態匯入或匯出語法,則
      1. 傳回 "module"
    3. 傳回 "commonjs"
  11. 如果 url 沒有任何副檔名,則
    1. 如果 packageType"module" 且啟用 --experimental-wasm-modulesurl 中的文件包含 WebAssembly 模組的標頭,則
      1. 傳回 "wasm"
    2. 如果 packageType 不是 null,則
      1. 傳回 packageType
    3. 如果啟用 --experimental-detect-module 且模組的來源包含靜態匯入或匯出語法,則
      1. 傳回 "module"
    4. 傳回 "commonjs"
  12. 傳回 undefined(會在載入階段拋出)。

LOOKUP_PACKAGE_SCOPE(url)

  1. scopeURL 成為 url
  2. scopeURL 不是檔案系統根目錄時,
    1. scopeURL 設定為 scopeURL 的父 URL。
    2. 如果 scopeURL"node_modules" 路徑區段結尾,傳回 null
    3. pjsonURL 成為 "package.json"scopeURL 中解析的結果。
    4. 如果 pjsonURL 中的文件存在,則
      1. 傳回 scopeURL
  3. 傳回 null

READ_PACKAGE_JSON(packageURL)

  1. pjsonURL 成為 "package.json"packageURL 中解析的結果。
  2. 如果 pjsonURL 中的文件不存在,則
    1. 傳回 null
  3. 如果 packageURL 中的文件無法解析為有效的 JSON,則
    1. 拋出 無效的套件組態 錯誤。
  4. 傳回 pjsonURL 中文件的已解析 JSON 來源。

自訂 ESM 規格符解析演算法#

模組自訂掛勾提供自訂 ESM 規格符解析演算法的機制。提供 ESM 規格符的 CommonJS 風格解析的範例為 commonjs-extension-resolution-loader