Модули: node:module API
Объект Module
Предоставляет общие вспомогательные методы при работе с экземплярами Module, переменной module, часто встречающейся в модулях CommonJS. Доступ к ней через import 'node:module' или require('node:module').
module.builtinModules
Список имён всех модулей, предоставляемых Node.js. Можно использовать для проверки, поддерживается ли модуль третьей стороной.
module в данном контексте — это не тот же объект, что и предоставляемый обёрткой модуля обёрткой модуля. Для доступа к нему требуется подключить модуль Module:
Модули MJS
// module.mjs
// In an ECMAScript module
import { builtinModules as builtin } from 'node:module';
Модули CJS
// module.cjs
// In a CommonJS module
const builtin = require('node:module').builtinModules;
module.createRequire(filename)
-
filename<строка> | <URL> Имя файла для построения функции require. Должен быть объектом URL файла, строкой URL файла или строкой абсолютного пути. - Возвращает: <require> Функция Require
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
// sibling-module.js is a CommonJS module.
const siblingModule = require('./sibling-module'); copy
module.isBuiltin(moduleName)
-
moduleName<строка> имя модуля - Возвращает: <логическое значение> возвращает true, если модуль встроенный, иначе возвращает false
import { isBuiltin } from 'node:module';
isBuiltin('node:fs'); // true
isBuiltin('fs'); // true
isBuiltin('wss'); // false copy
module.register(specifier[, parentURL][, options])
-
specifier<строка> | <URL> Фиксирующие крючки для регистрации; она должна быть той же строкой, что и передаваемаяimport(), за исключением того, что если она относительная, то она резолвится относительноparentURL. -
parentURL<строка> | <URL> Если нужно разрешитьspecifierотносительно базового URL, напримерimport.meta.url, вы можете передать этот URL здесь. По умолчанию:'data:' -
options<Объект>-
parentURL<строка> | <URL> Если нужно разрешитьspecifierотносительно базового URL, напримерimport.meta.url, вы можете передать этот URL здесь. Это свойство игнорируется, еслиparentURLзадано во втором аргументе. По умолчанию:'data:' -
data<любое> Любое произвольное, клонируемое значение JavaScript для передачи в крючокinitialize. -
transferList<Объект[]> передаваемые объекты для передачи в крючокinitialize.
-
Регистрирует модуль, экспортирующий крючки для настройки разрешения и загрузки модулей Node.js. См. крючки настройки.
module.syncBuiltinESMExports()
Метод module.syncBuiltinESMExports() обновляет все активные привязки встроенных модулей ES Модулей для соответствия свойствам экспорта CommonJS. Он не добавляет и не удаляет экспортируемые имена из ES Модулей.
const fs = require('node:fs');
const assert = require('node:assert');
const { syncBuiltinESMExports } = require('node:module');
fs.readFile = newAPI;
delete fs.readFileSync;
function newAPI() {
// ...
}
fs.newAPI = newAPI;
syncBuiltinESMExports();
import('node:fs').then((esmFS) => {
// It syncs the existing readFile property with the new value
assert.strictEqual(esmFS.readFile, newAPI);
// readFileSync has been deleted from the required fs
assert.strictEqual('readFileSync' in fs, false);
// syncBuiltinESMExports() does not remove readFileSync from esmFS
assert.strictEqual('readFileSync' in esmFS, true);
// syncBuiltinESMExports() does not add names
assert.strictEqual(esmFS.newAPI, undefined);
}); copy Настройка хуков
Включение
Разрешение и загрузка модулей можно настроить, зарегистрировав файл, который экспортирует набор хуков. Это можно сделать, используя метод register из node:module, который можно запустить перед кодом вашего приложения, используя флаг --import:
node --import ./register-hooks.js ./my-app.js copy
Модули MJS
// register-hooks.js
import { register } from 'node:module';
register('./hooks.mjs', import.meta.url);
Модули CJS
// register-hooks.js
const { register } = require('node:module');
const { pathToFileURL } = require('node:url');
register('./hooks.mjs', pathToFileURL(__filename)); Файл, переданный в --import , также может быть экспортом из зависимости:
node --import some-package/register ./my-app.js copy
Где some-package имеет поле "exports", определяющее экспорт /register для отображения файла, вызывающего register(), как в следующем примере register-hooks.js.
Использование --import гарантирует, что хуки будут зарегистрированы до импорта любых файлов приложения, включая точку входа приложения. В качестве альтернативы, register можно вызвать из точки входа, но динамическое import() необходимо для любого кода, который должен быть выполнен после регистрации хуков:
Модули MJS
import { register } from 'node:module';
register('http-to-https', import.meta.url);
// Because this is a dynamic `import()`, the `http-to-https` hooks will run
// to handle `./my-app.js` and any other files it imports or requires.
await import('./my-app.js');
Модули CJS
const { register } = require('node:module');
const { pathToFileURL } = require('node:url');
register('http-to-https', pathToFileURL(__filename));
// Because this is a dynamic `import()`, the `http-to-https` hooks will run
// to handle `./my-app.js` and any other files it imports or requires.
import('./my-app.js'); В этом примере мы регистрируем хуки http-to-https, но они будут доступны только для последующих импортированных модулей — в данном случае my-app.js и всего, на что оно ссылается через import (и необязательно require). Если бы import('./my-app.js') был статическим import './my-app.js', приложение было бы уже загружено до регистрации хуков http-to-https. Это из-за спецификации ES модулей, где статические импорты оцениваются сначала с листьев дерева, а затем обратно к стволу. Могут быть статические импорты внутри my-app.js, которые будут оценены только после динамического импорта my-app.js.
my-app.js также может быть CommonJS. Хуки настройки будут работать для любых модулей, на которые он ссылается через import (и необязательно require).
Наконец, если все, что вам нужно сделать, это зарегистрировать хуки до запуска вашего приложения и не создавать для этого отдельный файл, вы можете передать URL data: в --import:
node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("http-to-https", pathToFileURL("./"));' ./my-app.js copy Цепочки
Можно вызывать register более одного раза:
Модули MJS
// entrypoint.mjs
import { register } from 'node:module';
register('./foo.mjs', import.meta.url);
register('./bar.mjs', import.meta.url);
await import('./my-app.mjs');
Модули CJS
// entrypoint.cjs
const { register } = require('node:module');
const { pathToFileURL } = require('node:url');
const parentURL = pathToFileURL(__filename);
register('./foo.mjs', parentURL);
register('./bar.mjs', parentURL);
import('./my-app.mjs'); В этом примере зарегистрированные хуки сформируют цепочки. Эти цепочки выполняются в порядке LIFO (последний вошел, первый вышел). Если как foo.mjs , так и bar.mjs определяют хук resolve, они будут вызваны следующим образом (обратите внимание на порядок справа налево): стандартный Node.js ← ./foo.mjs ← ./bar.mjs (начиная с ./bar.mjs, затем ./foo.mjs, затем с функцией Node.js). То же самое относится ко всем другим хукам.
Зарегистрированные хуки также влияют на сам register. В этом примере bar.mjs будет разрешен и загружен через хуки, зарегистрированные foo.mjs (потому что хуки foo уже добавлены в цепочку). Это позволяет использовать хуки в языках, отличных от JavaScript, при условии, что ранее зарегистрированные хуки транслируются в JavaScript.
Метод register не может быть вызван из модуля, определяющего хуки.
Взаимодействие с хуками настройки модулей
Хуки настройки модулей выполняются в отдельном потоке, отличном от основного потока, в котором выполняется код приложения. Это означает, что изменение глобальных переменных не повлияет на другие потоки, и для взаимодействия между потоками необходимо использовать каналы сообщений.
Метод register может использоваться для передачи данных в хук initialize. Передаваемые данные могут включать передаваемые объекты, такие как порты.
Модули MJS
import { register } from 'node:module';
import { MessageChannel } from 'node:worker_threads';
// This example demonstrates how a message channel can be used to
// communicate with the hooks, by sending `port2` to the hooks.
const { port1, port2 } = new MessageChannel();
port1.on('message', (msg) => {
console.log(msg);
});
register('./my-hooks.mjs', {
parentURL: import.meta.url,
data: { number: 1, port: port2 },
transferList: [port2],
});
Модули CJS
const { register } = require('node:module');
const { pathToFileURL } = require('node:url');
const { MessageChannel } = require('node:worker_threads');
// This example showcases how a message channel can be used to
// communicate with the hooks, by sending `port2` to the hooks.
const { port1, port2 } = new MessageChannel();
port1.on('message', (msg) => {
console.log(msg);
});
register('./my-hooks.mjs', {
parentURL: pathToFileURL(__filename),
data: { number: 1, port: port2 },
transferList: [port2],
}); Хуки
Метод register можно использовать для регистрации модуля, который экспортирует набор хуков. Хуки — это функции, которые вызываются Node.js для настройки процесса разрешения и загрузки модулей. Экспортированные функции должны иметь определенные имена и сигнатуры, и они должны экспортироваться как именованные экспорты.
export async function initialize({ number, port }) {
// Receives data from `register`.
}
export async function resolve(specifier, context, nextResolve) {
// Take an `import` or `require` specifier and resolve it to a URL.
}
export async function load(url, context, nextLoad) {
// Take a resolved URL and return the source code to be evaluated.
} copy Хуки являются частью цепочки, даже если эта цепочка состоит только из одного пользовательского хука и стандартного хука, который всегда присутствует. Функции хуков вложены: каждая из них должна всегда возвращать простой объект, а цепочная обработка происходит в результате вызова каждой функцией next<hookName>(), являющегося ссылкой на хук последующего загрузчика (в порядке LIFO).
Хук, возвращающий значение без необходимого свойства, вызывает исключение. Хук, возвращающий без вызова next<hookName>() и без возвращения shortCircuit: true, также вызывает исключение. Эти ошибки помогают предотвратить непреднамеренные разрывы в цепочке. Возвращение shortCircuit: true из хука сигнализирует о том, что цепочка преднамеренно завершается на вашем хуке.
Хуки выполняются в отдельном потоке, изолированном от основного потока, где выполняется код приложения. Это означает, что это другой домен. Поток хуков может быть завершен основным потоком в любое время, поэтому не полагайтесь на асинхронные операции (например, console.log) для завершения.
initialize()
-
data<любой> Данные изregister(loader, import.meta.url, { data }).
Хук initialize предоставляет способ определения пользовательской функции, которая выполняется в потоке хуков при инициализации модуля хуков. Инициализация происходит при регистрации модуля хуков через register.
Этот хук может получать данные из вызова register, включая порты и другие передаваемые объекты. Возвращаемое значение хука initialize может быть <Promise>, в этом случае оно будет ожидаться до возобновления выполнения основного потока приложения.
Код настройки модуля:
// path-to-my-hooks.js
export async function initialize({ number, port }) {
port.postMessage(`increment: ${number + 1}`);
} copy Код вызывающей программы:
Модули MJS
import assert from 'node:assert';
import { register } from 'node:module';
import { MessageChannel } from 'node:worker_threads';
// This example showcases how a message channel can be used to communicate
// between the main (application) thread and the hooks running on the hooks
// thread, by sending `port2` to the `initialize` hook.
const { port1, port2 } = new MessageChannel();
port1.on('message', (msg) => {
assert.strictEqual(msg, 'increment: 2');
});
register('./path-to-my-hooks.js', {
parentURL: import.meta.url,
data: { number: 1, port: port2 },
transferList: [port2],
});
Модули CJS
const assert = require('node:assert');
const { register } = require('node:module');
const { pathToFileURL } = require('node:url');
const { MessageChannel } = require('node:worker_threads');
// This example showcases how a message channel can be used to communicate
// between the main (application) thread and the hooks running on the hooks
// thread, by sending `port2` to the `initialize` hook.
const { port1, port2 } = new MessageChannel();
port1.on('message', (msg) => {
assert.strictEqual(msg, 'increment: 2');
});
register('./path-to-my-hooks.js', {
parentURL: pathToFileURL(__filename),
data: { number: 1, port: port2 },
transferList: [port2],
});
resolve(specifier, context, nextResolve)
-
specifier<string> -
context<Object>-
conditions<string[]> Условия экспорта соответствующегоpackage.json -
importAttributes<Object> Объект, пары ключ-значение которого представляют атрибуты для импорта модуля -
parentURL<string> | <undefined> Модуль, импортирующий этот, или undefined, если это точка входа Node.js
-
-
nextResolve<Function> Следующийresolveобработчик в цепочке или стандартныйresolveобработчик Node.js после последнего пользовательскогоresolveобработчика - Returns: <Object> | <Promise>
-
format<string> | <null> | <undefined> Подсказка для обработчика загрузки (может быть проигнорирована)'builtin' | 'commonjs' | 'json' | 'module' | 'wasm' -
importAttributes<Object> | <undefined> Атрибуты импорта для использования при кэшировании модуля (необязательно; если опущены, будет использован входной параметр) -
shortCircuit<undefined> | <boolean> Сигнал, что этот обработчик намерен завершить цепочкуresolveобработчиков. По умолчанию:false -
url<string> Абсолютный URL, к которому приводит этот входной параметр
-
Предупреждение Несмотря на поддержку возвращаемых промисов и асинхронных функций, вызовы к
resolveмогут заблокировать основной поток, что повлияет на производительность.
Цепочка обработчиков resolve отвечает за указание Node.js, где найти и как кэшировать заданное import утверждение или выражение, или вызов require. Она может необязательно вернуть формат (такой как 'module') в качестве подсказки для load обработчика. Если формат указан, load обработчик в конечном итоге отвечает за предоставление конечного значения format (и он свободен игнорировать подсказку, предоставленную resolve); если resolve предоставляет format, требуется пользовательский load обработчик, даже если только для передачи значения в стандартный load обработчик Node.js.
Атрибуты типа импорта являются частью ключа кэша для сохранения загруженных модулей во внутренний кэш модулей. resolve обработчик отвечает за возвращение объекта importAttributes, если модуль должен быть кэширован с другими атрибутами, чем те, которые присутствуют в исходном коде.
Свойство conditions в context представляет собой массив условий для условий экспорта пакетов, которые применяются к этому запросу разрешения. Они могут использоваться для поиска условных сопоставлений в другом месте или для изменения списка при вызове стандартной логики разрешения.
Текущие условия экспорта пакетов всегда находятся в массиве context.conditions , переданном в обработчик. Для обеспечения поведения стандартного разрешения спецификатора модуля Node.js при вызове defaultResolve, массив context.conditions , переданный в него, должен включать все элементы массива context.conditions , первоначально переданного в resolve обработчик.
export async function resolve(specifier, context, nextResolve) {
const { parentURL = null } = context;
if (Math.random() > 0.5) { // Some condition.
// For some or all specifiers, do some custom logic for resolving.
// Always return an object of the form {url: <string>}.
return {
shortCircuit: true,
url: parentURL ?
new URL(specifier, parentURL).href :
new URL(specifier).href,
};
}
if (Math.random() < 0.5) { // Another condition.
// When calling `defaultResolve`, the arguments can be modified. In this
// case it's adding another value for matching conditional exports.
return nextResolve(specifier, {
...context,
conditions: [...context.conditions, 'another-condition'],
});
}
// Defer to the next hook in the chain, which would be the
// Node.js default resolve if this is the last user-specified loader.
return nextResolve(specifier);
} copy
load(url, context, nextLoad)
-
url<string> URL, возвращённый цепочкойresolveобработчиков -
context<Object>-
conditions<string[]> Условия экспорта соответствующегоpackage.json -
format<string> | <null> | <undefined> Формат, необязательно предоставленный цепочкойresolveобработчиков -
importAttributes<Object>
-
-
nextLoad<Function> Следующийloadобработчик в цепочке или стандартныйloadобработчик Node.js после последнего пользовательскогоloadобработчика - Returns: <Object>
-
format<string> -
shortCircuit<undefined> | <boolean> Сигнал, что этот обработчик намерен завершить цепочкуresolveобработчиков. По умолчанию:false -
source<string> | <ArrayBuffer> | <TypedArray> Источник для оценки Node.js
-
Обработчик load предоставляет способ определить пользовательский метод определения того, как URL должен интерпретироваться, извлекаться и анализироваться. Он также отвечает за валидацию атрибутов импорта.
Конечное значение format должно быть одним из следующих:
format |
Описание | Допустимые типы для source возвращаемых load
|
|---|---|---|
'builtin' |
Загрузка встроенного модуля Node.js | Не применимо |
'commonjs' |
Загрузка модуля Node.js CommonJS | { string, ArrayBuffer, TypedArray, null, undefined } |
'json' |
Загрузка файла JSON | { string, ArrayBuffer, TypedArray } |
'module' |
Загрузка модуля ES | { string, ArrayBuffer, TypedArray } |
'wasm' |
Загрузка модуля WebAssembly | { ArrayBuffer, TypedArray } |
Значение source игнорируется для типа 'builtin', так как в настоящее время невозможно заменить значение встроенного (ядерного) модуля Node.js.
Опускание или предоставление source для 'commonjs' имеет совершенно разные последствия:
- При предоставлении
source, все вызовыrequireиз этого модуля будут обрабатываться загрузчиком ESM с зарегистрированнымиresolveиloadобработчиками; все вызовыrequire.resolveиз этого модуля будут обрабатываться загрузчиком ESM с зарегистрированнымиresolveобработчиками; будет доступен только подмножество API CommonJS (например, нетrequire.extensions, нетrequire.cache, нетrequire.resolve.paths) и подмена кода (monkey-patching) в загрузчике модулей CommonJS не будет применена. - Если
sourceне определено илиnull, оно будет обработано загрузчиком модулей CommonJS, и вызовыrequire/require.resolveне будут проходить через зарегистрированные обработчики. Это поведение для нулевого или неопределенногоsourceявляется временным — в будущем нулевое или неопределенное значениеsourceне будет поддерживаться.
При запуске node с --experimental-default-type=commonjs, внутренняя реализация load Node.js, которая является значением next для последнего обработчика в цепочке load, возвращает null для source когда format равно 'commonjs' для обеспечения обратной совместимости. Вот пример обработчика, который бы выбрал использование нестандартного поведения:
import { readFile } from 'node:fs/promises';
export async function load(url, context, nextLoad) {
const result = await nextLoad(url, context);
if (result.format === 'commonjs') {
result.source ??= await readFile(new URL(result.responseURL ?? url));
}
return result;
} copy Предупреждение: Обработчик ESM
loadи именованные экспорты из модулей CommonJS несовместимы. Попытка их совместного использования приведет к пустому объекту из импорта. В будущем это может быть исправлено.
Эти типы соответствуют классам, определённым в ECMAScript.
- Конкретный объект
ArrayBufferявляетсяSharedArrayBuffer. - Конкретный объект
TypedArrayявляетсяUint8Array.
Если исходное значение текстового формата (например, 'json', 'module' ) не является строкой, оно преобразуется в строку с помощью util.TextDecoder.
Обработчик load предоставляет способ определения пользовательского метода для получения исходного кода разрешенного URL. Это позволило бы загрузчику потенциально избегать чтения файлов с диска. Также это можно использовать для сопоставления нераспознанного формата с поддерживаемым, например, yaml в module.
export async function load(url, context, nextLoad) {
const { format } = context;
if (Math.random() > 0.5) { // Some condition
/*
For some or all URLs, do some custom logic for retrieving the source.
Always return an object of the form {
format: <string>,
source: <string|buffer>,
}.
*/
return {
format,
shortCircuit: true,
source: '...',
};
}
// Defer to the next hook in the chain.
return nextLoad(url);
} copy В более сложных сценариях это также можно использовать для преобразования неподдерживаемого источника в поддерживаемый (см. Примеры ниже).
Примеры
Различные обработчики настройки модулей могут использоваться вместе для достижения широкого спектра настроек поведения загрузки и выполнения кода в Node.js.
Импорт из HTTPS
В текущей версии Node.js спецификаторы, начинающиеся с https:// являются экспериментальными (см. Импорт из HTTPS и HTTP).
Нижеследующий обработчик регистрирует обработчики для обеспечения первоначальной поддержки таких спецификаторов. Хотя это может показаться существенным улучшением функциональности ядра Node.js, существуют значительные недостатки при фактическом использовании этих обработчиков: производительность намного ниже, чем при загрузке файлов с диска, нет кэширования и нет безопасности.
// https-hooks.mjs
import { get } from 'node:https';
export function load(url, context, nextLoad) {
// For JavaScript to be loaded over the network, we need to fetch and
// return it.
if (url.startsWith('https://')) {
return new Promise((resolve, reject) => {
get(url, (res) => {
let data = '';
res.setEncoding('utf8');
res.on('data', (chunk) => data += chunk);
res.on('end', () => resolve({
// This example assumes all network-provided JavaScript is ES module
// code.
format: 'module',
shortCircuit: true,
source: data,
}));
}).on('error', (err) => reject(err));
});
}
// Let Node.js handle all other URLs.
return nextLoad(url);
} copy // main.mjs
import { VERSION } from 'https://coffeescript.org/browser-compiler-modern/coffeescript.js';
console.log(VERSION); copy Используя приведенный модуль обработчиков, выполнение node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./https-hooks.mjs"));' ./main.mjs выводит текущую версию CoffeeScript в соответствии с модулем по URL в main.mjs.
Транспиляция
Источники, которые Node.js не понимает, могут быть преобразованы в JavaScript с помощью обработчика load.
Это менее производительно, чем транспиляция исходных файлов перед запуском Node.js; обработчики транспилятора должны использоваться только в целях разработки и тестирования.
// coffeescript-hooks.mjs
import { readFile } from 'node:fs/promises';
import { dirname, extname, resolve as resolvePath } from 'node:path';
import { cwd } from 'node:process';
import { fileURLToPath, pathToFileURL } from 'node:url';
import coffeescript from 'coffeescript';
const extensionsRegex = /\.(coffee|litcoffee|coffee\.md)$/;
export async function load(url, context, nextLoad) {
if (extensionsRegex.test(url)) {
// CoffeeScript files can be either CommonJS or ES modules, so we want any
// CoffeeScript file to be treated by Node.js the same as a .js file at the
// same location. To determine how Node.js would interpret an arbitrary .js
// file, search up the file system for the nearest parent package.json file
// and read its "type" field.
const format = await getPackageType(url);
const { source: rawSource } = await nextLoad(url, { ...context, format });
// This hook converts CoffeeScript source code into JavaScript source code
// for all imported CoffeeScript files.
const transformedSource = coffeescript.compile(rawSource.toString(), url);
return {
format,
shortCircuit: true,
source: transformedSource,
};
}
// Let Node.js handle all other URLs.
return nextLoad(url);
}
async function getPackageType(url) {
// `url` is only a file path during the first iteration when passed the
// resolved url from the load() hook
// an actual file path from load() will contain a file extension as it's
// required by the spec
// this simple truthy check for whether `url` contains a file extension will
// work for most projects but does not cover some edge-cases (such as
// extensionless files or a url ending in a trailing space)
const isFilePath = !!extname(url);
// If it is a file path, get the directory it's in
const dir = isFilePath ?
dirname(fileURLToPath(url)) :
url;
// Compose a file path to a package.json in the same directory,
// which may or may not exist
const packagePath = resolvePath(dir, 'package.json');
// Try to read the possibly nonexistent package.json
const type = await readFile(packagePath, { encoding: 'utf8' })
.then((filestring) => JSON.parse(filestring).type)
.catch((err) => {
if (err?.code !== 'ENOENT') console.error(err);
});
// If package.json existed and contained a `type` field with a value, voilà
if (type) return type;
// Otherwise, (if not at the root) continue checking the next directory up
// If at the root, stop and return false
return dir.length > 1 && getPackageType(resolvePath(dir, '..'));
} copy # main.coffee
import { scream } from './scream.coffee'
console.log scream 'hello, world'
import { version } from 'node:process'
console.log "Brought to you by Node.js version #{version}" copy # scream.coffee export scream = (str) -> str.toUpperCase() copy
Выполнение node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./coffeescript-hooks.mjs"));' ./main.coffee приведет к преобразованию main.coffee в JavaScript после загрузки исходного кода с диска, но перед выполнением его Node.js; и так далее для любых файлов .coffee, .litcoffee или .coffee.md, ссылающихся через инструкции import любого загруженного файла.
Карты импорта
Предыдущие два примера определяли обработчики load . Это пример обработчика resolve . Этот модуль обработчиков читает файл import-map.json , который определяет, какие спецификаторы переопределять на другие URL (это очень упрощённая реализация небольшого подмножества спецификации «карты импорта»).
// import-map-hooks.js
import fs from 'node:fs/promises';
const { imports } = JSON.parse(await fs.readFile('import-map.json'));
export async function resolve(specifier, context, nextResolve) {
if (Object.hasOwn(imports, specifier)) {
return nextResolve(imports[specifier], context);
}
return nextResolve(specifier, context);
} copy С этими файлами:
// main.js import 'a-module'; copy
// import-map.json
{
"imports": {
"a-module": "./some-module.js"
}
} copy // some-module.js
console.log('some module!'); copy Выполнение node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./import-map-hooks.js"));' main.js должно вывести some module!.
Поддержка карты исходного кода v3
Вспомогательные функции для взаимодействия с кэшем карт исходного кода. Этот кэш заполняется при включении разбора карт исходного кода и обнаружении директив включения карт исходного кода в футере модулей.
Чтобы включить разбор карт исходного кода, Node.js необходимо запустить со флагом --enable-source-maps, или с включённым покрытием кода, установив NODE_V8_COVERAGE=dir.
Модули MJS
// module.mjs
// In an ECMAScript module
import { findSourceMap, SourceMap } from 'node:module';
Модули CJS
// module.cjs
// In a CommonJS module
const { findSourceMap, SourceMap } = require('node:module');
module.findSourceMap(path)
-
path<строка> - Возвращает: <модуль.SourceMap> | <неопределено> Возвращает
module.SourceMapесли карта исходного кода найдена,undefinedв противном случае.
path — это разрешённый путь к файлу, для которого должна быть получена соответствующая карта исходного кода.
Класс: module.SourceMap
new SourceMap(payload[, { lineLengths }])
-
payload<объект> -
lineLengths<массив чисел>
Создаёт новый экземпляр sourceMap.
payload — это объект с ключами, соответствующими формату карты исходного кода v3:
-
file: <строка> -
version: <число> -
sources: <массив строк> -
sourcesContent: <массив строк> -
names: <массив строк> -
mappings: <строка> -
sourceRoot: <строка>
lineLengths — это необязательный массив длин каждой строки в сгенерированном коде.
sourceMap.payload
- Возвращает: <объект>
Геттер для данных, используемых для создания экземпляра SourceMap.
sourceMap.findEntry(lineOffset, columnOffset)
-
lineOffset<число> Смещение номера строки (с нуля) в сгенерированном исходном коде -
columnOffset<число> Смещение номера столбца (с нуля) в сгенерированном исходном коде - Возвращает: <объект>
На основе смещения строки и столбца в сгенерированном файле исходного кода возвращает объект, представляющий диапазон SourceMap в исходном файле, если он найден, или пустой объект, если нет.
Возвращаемый объект содержит следующие ключи:
- generatedLine: <число> Смещение строки начала диапазона в сгенерированном исходном коде
- generatedColumn: <число> Смещение столбца начала диапазона в сгенерированном исходном коде
- originalSource: <строка> Имя файла исходного кода, как указано в SourceMap
- originalLine: <число> Смещение строки начала диапазона в исходном коде
- originalColumn: <число> Смещение столбца начала диапазона в исходном коде
- name: <строка>
Возвращаемое значение представляет собой исходный диапазон, как он отображается в SourceMap, на основе смещений с нуля, а не индексированных с единицы номеров строки и столбца, как они отображаются в сообщениях об ошибках и объектах CallSite.
Чтобы получить соответствующие номера строки и столбца с индексом 1 из lineNumber и columnNumber, как они сообщаются стеками ошибок и объектами CallSite, используйте sourceMap.findOrigin(lineNumber, columnNumber)
sourceMap.findOrigin(lineNumber, columnNumber)
-
lineNumber<число> Номер строки (с индексом 1) вызова в сгенерированном исходном коде -
columnNumber<число> Номер столбца (с индексом 1) вызова в сгенерированном исходном коде - Возвращает: <объект>
На основе номера строки (с индексом 1) и номера столбца (с индексом 1) вызова в сгенерированном исходном коде находит соответствующее местоположение вызова в исходном коде.
Если заданные номер строки (с индексом 1) и номер столбца (с индексом 1) не найдены ни в одной карте исходного кода, возвращается пустой объект. В противном случае возвращаемый объект содержит следующие ключи:
- name: <строка> | <неопределено> Имя диапазона в карте исходного кода, если оно было предоставлено
- fileName: <строка> Имя файла исходного кода, как указано в SourceMap
- lineNumber: <число> Номер строки (с индексом 1) соответствующего вызова в исходном коде
- columnNumber: <число> Номер столбца (с индексом 1) соответствующего вызова в исходном коде
© 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/api/module.html