Spec-Zone.ru › Node.js 20 LTS

Модули: ECMAScript модули

История
Версия Изменения
v20.10.0

Добавлена экспериментальная поддержка атрибутов импорта.

v20.0.0

Обработчики настройки модулей выполняются вне основного потока.

v18.6.0, v16.17.0

Добавлена поддержка цепочки обработчиков настройки модулей.

v17.1.0, v16.14.0

Добавлена экспериментальная поддержка утверждений импорта.

v17.0.0, v16.12.0

Объединены обработчики настройки, удалены getFormat, getSource, transformSource, и getGlobalPreloadCode обработчики, добавлены load и globalPreload обработчики, разрешено возвращать format из resolve или load обработчиков.

v14.8.0

Отменён флаг Top-Level Await.

v15.3.0, v14.17.0, v12.22.0

Стабилизирована реализация модулей.

v14.13.0, v12.20.0

Поддержка обнаружения именованных экспортов CommonJS.

v14.0.0, v13.14.0, v12.20.0

Удалено предупреждение об экспериментальных модулях.

v13.2.0, v12.17.0

Загрузка ECMAScript модулей больше не требует флага командной строки.

v12.0.0

Добавлена поддержка ES модулей с использованием .js расширения файла через package.json "type" поле.

v8.5.0

Добавлен в: v8.5.0

Устойчивость: 2 - Стабильно

Введение

ECMAScript модули — это официальный стандартный формат для упаковки кода JavaScript для повторного использования. Модули определяются с помощью различных import и export операторов.

Следующий пример ES модуля экспортирует функцию:

// addTwo.mjs
function addTwo(num) {
  return num + 2;
}

export { addTwo }; copy

Следующий пример ES модуля импортирует функцию из addTwo.mjs:

// app.mjs
import { addTwo } from './addTwo.mjs';

// Prints: 6
console.log(addTwo(4)); copy

Node.js полностью поддерживает ECMAScript модули в соответствии с текущим спецификацией и обеспечивает меж совместимость между ними и исходным форматом модулей CommonJS.

Включение

Node.js имеет две системы модулей: модули CommonJS и ECMAScript модули.

Авторы могут указать Node.js интерпретировать JavaScript как ES модуль через .mjs расширение файла, package.json "type" поле со значением "module", --input-type флаг со значением "module", или --experimental-default-type флаг со значением "module". Это явные маркеры кода, предназначенного для выполнения в качестве ES модуля.

Обратно, авторы могут указать Node.js интерпретировать JavaScript как CommonJS через .cjs расширение файла, package.json "type" поле со значением "commonjs", --input-type флаг со значением "commonjs", или --experimental-default-type флаг со значением "commonjs".

Когда код не содержит явных маркеров для какой-либо системы модулей, Node.js проверит исходный код модуля на наличие синтаксиса ES модулей. Если такой синтаксис найден, Node.js выполнит код как ES модуль; в противном случае модуль будет выполнен как CommonJS. Подробнее см. Определение системы модулей.

Пакеты

Этот раздел перенесен в Модули: Пакеты.

import Спецификаторы

Терминология

Спецификатор оператора import — это строка после ключевого слова from, например, 'node:path' в import { sep } from '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" copy

Корень тома можно указать через /, //, или file:///. Учитывая различия между разрешением URL и путей (таких как особенности кодирования процентов), рекомендуется использовать url.pathToFileURL при импорте пути.

data: импорты
Добавлен в: v12.10.0

data: URL-адреса поддерживаются для импорта со следующими типами MIME:

  • 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' }; copy

data: URL-адреса разрешают только обычные спецификаторы для встроенных модулей и абсолютные спецификаторы. Разрешение относительных спецификаторов не работает, потому что data: не является специальной схемой. Например, попытка загрузить ./foo из data:text/javascript,import "./foo"; не приводит к разрешению, потому что нет понятия относительного разрешения для data: URL-адресов.

node: импорты
История
Версия Изменения
v16.0.0, v14.18.0

Добавлена поддержка импорта node: в require(...).

v14.13.1, v12.20.0

Добавлен в: v14.13.1, v12.20.0

node: URL-адреса поддерживаются в качестве альтернативного способа загрузки встроенных модулей Node.js. Эта схема URL позволяет ссылаться на встроенные модули с помощью допустимых абсолютных строк URL-адресов.

import fs from 'node:fs/promises'; copy

Атрибуты импорта

История
Версия Изменения
v20.10.0

Переход от утверждений импорта к атрибутам импорта.

v17.1.0, v16.14.0

Добавлен в: v17.1.0, v16.14.0

Устойчивость: 1.1 - Активное развитие

Эта функция ранее называлась «утверждения импорта», и использовалось ключевое слово assert вместо with. Все используемые в коде ключевые слова assert должны быть обновлены на with.

Предложение Атрибуты импорта добавляет встроенный синтаксис для операторов импорта модулей для передачи дополнительной информации вместе со спецификатором модуля.

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

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

Node.js поддерживает следующие type значения, для которых атрибут является обязательным:

Атрибут type Необходим для
'json' JSON модули

Встроенные модули

Ядерные модули предоставляют именованные экспорты своего публичного API. Также предоставляется экспорт по умолчанию, который соответствует значению экспорта CommonJS. Экспорт по умолчанию может быть использован, среди прочего, для изменения именованных экспортов. Именованные экспорты встроенных модулей обновляются только путем вызова module.syncBuiltinESMExports().

import EventEmitter from 'node:events';
const e = new EventEmitter(); copy
import { readFile } from 'node:fs';
readFile('./foo.txt', (err, source) => {
  if (err) {
    console.error(err);
  } else {
    console.log(source);
  }
}); copy
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; copy

import() выражения

Динамические import() поддерживаются как в CommonJS, так и в ES модулях. В CommonJS модулях он может использоваться для загрузки ES модулей.

import.meta

  • <Объект>

Свойство import.meta meta — это Object, содержащее следующие свойства.

import.meta.dirname

Добавлен в: v20.11.0
Устойчивость: 1.2 — Кандидат в релиз
  • <строка> Имя каталога текущего модуля. Оно совпадает с path.dirname() пути к import.meta.filename.

Примечание: присутствует только в модулях file:.

import.meta.filename

Добавлен в: v20.11.0
Устойчивость: 1.2 — Кандидат в релиз
  • <строка> Полный абсолютный путь и имя файла текущего модуля, с
  • разрешенными символическими ссылками.
  • Это соответствует url.fileURLToPath() объекта
  • import.meta.url.

Примечание: доступно только для локальных модулей. Модули, не использующие протокол file:, не предоставляют это свойство.

import.meta.url

  • <строка> Абсолютный file: URL модуля.

Определяется точно так же, как в браузерах, предоставляя URL текущего файла модуля.

Это позволяет использовать полезные шаблоны, такие как загрузка файлов относительно текущего:

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

import.meta.resolve(specifier)

История
Версия Изменения
v20.6.0

Убрать флаг import.meta.resolve, при этом параметр parentURL по-прежнему активен.

v20.6.0

Этот API больше не генерирует исключение при обращении к file: URL, которые не отображаются в существующем файле на локальном файловой системе.

v20.0.0

Этот API теперь возвращает строку синхронно, а не промис.

v16.2.0, v14.18.0

Добавлена поддержка объекта WHATWG URL для параметра parentURL.

v13.9.0, v12.16.2

Добавлен в: v13.9.0, v12.16.2

Устойчивость: 1.2 — Кандидат в релиз
  • specifier <строка> Спецификатор модуля для разрешения относительно текущего модуля.
  • Возвращает: <строка> Абсолютный 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 copy

Поддерживаются все функции разрешения модулей Node.js. Разрешение зависимостей подчиняется разрешенным экспортам в пакете.

Примечания:

  • Это может привести к синхронным операциям с файловой системой, что может повлиять на производительность, как и require.resolve.
  • Эта функция недоступна внутри пользовательских загрузчиков (это создаст тупик).

Нестандартный API:

При использовании флага --experimental-import-meta-resolve, функция принимает второй аргумент:

  • parent <строка> | <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() для загрузки ES-модуля из CommonJS-модуля.

Пространства имен 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 copy

Представление пространства имён ECMAScript Module для CommonJS-модуля всегда является пространством имён с ключом экспорта default, указывающим на значение CommonJS module.exports.

Этот экзотический объект пространства имён модуля можно непосредственно наблюдать при использовании 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 copy

Для лучшей совместимости с существующим использованием в экосистеме JavaScript, Node.js также пытается определить именованные экспорты CommonJS каждого импортированного CommonJS-модуля, чтобы предоставить их как отдельные экспорты ES-модулей с помощью процесса статического анализа.

Например, рассмотрим CommonJS-модуль, написанный:

// cjs.cjs
exports.name = 'exported'; copy

Предыдущий модуль поддерживает именованные импорты в 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' } copy

Как видно из последнего примера вывода экзотического объекта пространства имён модуля, экспорт name копируется из объекта module.exports и устанавливается непосредственно в пространстве имён ES-модуля при импорте модуля.

Обновления живой привязки или новые экспорты, добавленные к module.exports, не обнаруживаются для этих именованных экспортов.

Обнаружение именованных экспортов основано на общих синтаксических шаблонах, но не всегда правильно обнаруживает именованные экспорты. В таких случаях использование формы импорта по умолчанию, описанной выше, может быть лучшим вариантом.

Обнаружение именованных экспортов охватывает многие распространенные шаблоны экспорта, шаблоны переэкспорта и результаты работы инструментов сборки и транспайлеров. См. cjs-module-lexer для точной семантики реализованной функциональности.

Отличия между ES-модулями и CommonJS

Отсутствуют require, exports, или module.exports

В большинстве случаев ES-модуль import может использоваться для загрузки CommonJS-модулей.

Если необходимо, функцию require можно создать внутри ES-модуля, используя module.createRequire().

Отсутствуют __filename или __dirname

Эти переменные CommonJS недоступны в ES-модулях.

Случаи использования __filename и __dirname можно воспроизвести с помощью import.meta.filename и import.meta.dirname.

Отсутствует загрузка плагинов

Плагины в настоящее время не поддерживаются с импортами ES-модулей.

Их можно загрузить с помощью module.createRequire() или process.dlopen.

Отсутствует require.resolve

Относительное разрешение можно обработать через new URL('./local', import.meta.url).

Для полного require.resolve замещения существует API import.meta.resolve.

В качестве альтернативы можно использовать module.createRequire().

Отсутствует NODE_PATH

NODE_PATH не участвует в разрешении import спецификаторов. Пожалуйста, используйте символические ссылки, если это поведение нужно.

Отсутствуют require.extensions

require.extensions не используется import. Модульные пользовательские крючки могут предоставить замену.

Отсутствует require.cache

require.cache не используется import, так как у загрузчика ES-модулей есть свой отдельный кэш.

JSON-модули

Устойчивость: 1 — Экспериментальная

Файлы JSON могут быть проинициализированы оператором import:

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

Синтаксис with { type: 'json' } обязателен; см. Атрибуты импорта.

Импортированный JSON экспонирует только экспорт default. Поддержка именованных экспортов отсутствует. В кэше CommonJS создаётся запись, чтобы избежать дублирования. Тот же объект возвращается в CommonJS, если JSON-модуль уже был импортирован из того же пути.

Модули Wasm

Устойчивость: 1 — Экспериментальная

Импорт модулей WebAssembly поддерживается под флагом --experimental-wasm-modules, что позволяет импортировать любые файлы .wasm как обычные модули, а также поддерживает их импорты модулей.

Эта интеграция соответствует Предложению по интеграции ES-модулей для WebAssembly.

Например, файл index.mjs содержащий:

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

выполненный под:

node --experimental-wasm-modules index.mjs copy

предоставит интерфейс экспорта для инициализации module.wasm.

Ключевое слово `await` на верхнем уровне модуля ECMAScript

Добавлена в: v14.8.0

Ключевое слово `await` может использоваться в теле модуля ECMAScript на верхнем уровне.

Предположим, у нас есть a.mjs,

export const five = await Promise.resolve(5); copy

И b.mjs, с

import { five } from './a.mjs';

console.log(five); // Logs `5` copy
node b.mjs # works copy

Если выражение `await` на верхнем уровне модуля никогда не разрешается, процесс Node.js завершится со статусом ошибки.

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

Импорты HTTPS и HTTP

Уровень стабильности: 1 - Экспериментально

Поддержка импорта модулей, основанных на сети, с использованием `import` и `require`, доступна при включении флага --experimental-network-imports. Это позволяет использовать импорты, похожие на веб-браузерные, в Node.js, но с некоторыми отличиями из-за соображений стабильности и безопасности, которые отличаются при работе в привилегированной среде, в отличие от браузерной среды.

Импорты ограничены HTTP/1

Автоматическое согласование протокола для HTTP/2 и HTTP/3 пока не поддерживается.

HTTP ограничен адресами обратной петли

http: уязвим к атакам «человек посередине» и не разрешен для использования с адресами за пределами IPv4-адресного 127.0.0.0/8 (127.0.0.1 до 127.255.255.255) и IPv6-адреса ::1. Поддержка импорта по HTTP предназначена для локального разработки.

Аутентификация никогда не отправляется на сервер назначения.

Заголовки Authorization, Cookie, и Proxy-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 }); copy
// 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
} copy

Загрузка по сети не включена по умолчанию

Пока для загрузки ресурсов по http: или https: требуется флаг --experimental-network-imports. В будущем будет использован другой механизм для принудительного управления доступом. Требуется явное включение, чтобы предотвратить непреднамеренное использование потенциально изменчивого состояния зависимостями, что может повлиять на надёжность приложений Node.js.

Загрузчики

Документация по Загрузчикам теперь находится по адресу Модули: Настраиваемые крючки.

Резолюция и алгоритм загрузки

Функции

По умолчанию резольвер имеет следующие свойства:

  • Резолюция на основе FileURL, как используется в ES модулях
  • Резолюция относительных и абсолютных URL
  • Отсутствуют расширения по умолчанию
  • Отсутствуют главные папки
  • Поиск резолюции пакетов с пустыми спецификаторами через node_modules
  • Не генерирует ошибки при неизвестных расширениях или протоколах
  • Может предоставить подсказку о формате загрузке

По умолчанию загрузчик имеет следующие свойства

  • Поддержка загрузки встроенных модулей через node: URL
  • Поддержка загрузки модулей "inline" через data: URL
  • Поддержка загрузки модулей file:
  • Возвращает ошибку при любом другом протоколе URL
  • Возвращает ошибку при неизвестных расширениях для file: загрузки (поддерживаются только .cjs, .js, и .mjs )

Алгоритм резолюции

Алгоритм загрузки спецификатора ES модуля задаётся методом ESM_RESOLVE ниже. Он возвращает резолированный URL для спецификатора модуля относительно parentURL.

Алгоритм резолюции определяет полный резолированный URL для загрузки модуля, а также его предполагаемый формат модуля. Алгоритм резолюции не определяет, может ли быть загружен протокол резолированного URL или разрешены ли расширения файлов, вместо этого эти валидации применяются Node.js во время фазы загрузки (например, если ему было предложено загрузить URL с протоколом, который не является file:, data:, node:, или если --experimental-network-imports включен, https:).

Алгоритм также пытается определить формат файла на основе расширения (см. алгоритм ESM_FILE_FORMAT ниже). Если он не распознаёт расширение файла (например, если это не .mjs, .cjs, или .json), то возвращается формат undefined, который вызовет ошибку во время фазы загрузки.

Алгоритм определения формата модуля резолированного URL предоставляется методом ESM_FILE_FORMAT, который возвращает уникальный формат модуля для любого файла. Формат "module" возвращается для ECMAScript модуля, в то время как формат "commonjs" используется для указания загрузки через устаревший загрузчик CommonJS. Дополнительные форматы, такие как "addon", могут быть расширены в будущих обновлениях.

Во всех следующих алгоритмах все ошибки подпрограмм распространяются как ошибки этих основных процедур, если не указано иное.

defaultConditions — массив имён условных сред, ["node", "import"].

Резольвер может выдать следующие ошибки:

  • Неверный спецификатор модуля: спецификатор модуля является недопустимым URL, именем пакета или подпутем пакета.
  • Недопустивая конфигурация пакета: конфигурация package.json недействительна или содержит недействительную конфигурацию.
  • Неверная цель пакета: экспорт или импорт пакета определяет целевой модуль для пакета, который является недопустимым типом или строковой целью.
  • Путь пакета не экспортирован: экспорт пакета не определяет или не разрешает целевой подпуть в пакете для данного модуля.
  • Импорт пакета не определён: импорты пакета не определяют спецификатор.
  • Модуль не найден: запрашиваемый пакет или модуль не существует.
  • Неподдерживаемый импорт каталога: резолированный путь соответствует каталогу, который не является поддерживаемой целью для импорта модулей.

Спецификация алгоритма резолюции

ESM_RESOLVE(specifier, parentURL)

  1. Пусть resolved будет undefined.
  2. Если specifier является корректным URL, тогда
    1. Установить resolved в результат парсинга и ресериализации specifier как URL.
  3. В противном случае, если specifier начинается с "/", "./" или "../", тогда
    1. Установить resolved в результат резолюции URL specifier относительно parentURL.
  4. В противном случае, если specifier начинается с "#", тогда
    1. Установить resolved в результат PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, defaultConditions).
  5. В противном случае,
    1. Примечание: specifier теперь является спецификатором без имени пакета.
    2. Установить resolved в результат PACKAGE_RESOLVE(specifier, parentURL).
  6. Пусть format будет undefined.
  7. Если resolved — это URL "file:", тогда
    1. Если resolved содержит какие-либо кодировки процентов "/" или "\" (соответственно "%2F" и "%5C"), то
      1. Выдать ошибку Неверный спецификатор модуля.
    2. Если файл по адресу resolved является каталогом, тогда
      1. Выдать ошибку Неподдерживаемый импорт каталога.
    3. Если файла по адресу resolved не существует, то
      1. Выдать ошибку Модуль не найден.
    4. Установить resolved в реальный путь resolved, сохраняя те же параметры запроса URL и фрагменты.
    5. Установить format в результат ESM_FILE_FORMAT(resolved).
  8. В противном случае,
    1. Установить format в формат модуля, связанный с типом содержимого URL resolved.
  9. Вернуть format и resolved фазе загрузки

PACKAGE_RESOLVE(packageSpecifier, parentURL)

```
  1. Assert: specifier начинается с "#".
  2. Если specifier точно равен "#" или начинается с "#/", то
    1. Выбросить ошибку Invalid Module Specifier.
  3. Пусть packageURL будет результатом LOOKUP_PACKAGE_SCOPE(parentURL).
  4. Если packageURL не null, то
    1. Пусть pjson будет результатом READ_PACKAGE_JSON(packageURL).
    2. Если pjson.imports — непустой объект, то
      1. Пусть resolved будет результатом PACKAGE_IMPORTS_EXPORTS_RESOLVE( specifier, pjson.imports, packageURL, true, conditions).
      2. Если resolved не null и не undefined, вернуть resolved.
  5. Выбросить ошибку Package Import Not Defined.

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

  1. Если matchKey — ключ в matchObj и не содержит "*", то
    1. Пусть target — значение matchObj[matchKey].
    2. Вернуть результат PACKAGE_TARGET_RESOLVE(packageURL, target, null, isImports, conditions).
  2. Пусть expansionKeys — список ключей в matchObj, содержащих только один "*", отсортированный по функции сортировки PATTERN_KEY_COMPARE, которая упорядочивает по убыванию специфичности.
  3. Для каждого ключа expansionKey в expansionKeys выполнить
    1. Пусть patternBase — подстрока expansionKey до, но не включая первый символ "*".
    2. Если matchKey начинается с patternBase, но не равно ему, то
      1. Пусть patternTrailer — подстрока expansionKey с индекса, следующего за первым символом "*".
      2. Если patternTrailer имеет нулевую длину или matchKey оканчивается на patternTrailer и длина 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. Assert: keyA оканчивается на "/" или содержит только один "*".
  2. Assert: keyB оканчивается на "/" или содержит только один "*".
  3. Пусть baseLengthA — индекс "*" в keyA плюс один, если keyA содержит "*", или длина keyA иначе.
  4. Пусть baseLengthB — индекс "*" в keyB плюс один, если keyB содержит "*", или длина 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)

ESM_FILE_FORMAT(url)

LOOKUP_PACKAGE_SCOPE(url)

READ_PACKAGE_JSON(packageURL)

DETECT_MODULE_SYNTAX(source)

END_OF_DOCUMENT_MARKER

Настройка алгоритма разрешения спецификаторов ESM

Модульные хуки настройки предоставляют механизм для настройки алгоритма разрешения спецификаторов ESM. Пример, обеспечивающий разрешение в стиле CommonJS для спецификаторов ESM, представлен в commonjs-extension-resolution-loader.

© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v20.x/docs/api/esm.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API