Node.js v20.7.0 文档


目录

模块:node:module API#

Module 对象#

在与 Module 的实例交互时提供通用实用方法,module 变量经常出现在 CommonJS 模块中。 通过 import 'node:module'require('node:module') 访问。

module.builtinModules#

Node.js 提供的所有模块的名称列表。 可用于验证模块是否由第三方维护。

此上下文中的 module模块封装器 提供的对象不同。 要访问它,需要 Module 模块:

// module.mjs
// In an ECMAScript module
import { builtinModules as builtin } from 'node:module';// module.cjs
// In a CommonJS module
const builtin = require('node:module').builtinModules;

module.createRequire(filename)#

  • filename <string> | <URL> 用于构造 require 函数的文件名。 必须是文件网址对象、文件网址字符串、或绝对路径字符串。
  • 返回: <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'); 

module.isBuiltin(moduleName)#

  • moduleName <string> 模块名称
  • 返回: <boolean> 如果模块是内置的,则返回 true,否则返回 false
import { isBuiltin } from 'node:module';
isBuiltin('node:fs'); // true
isBuiltin('fs'); // true
isBuiltin('wss'); // false 

module.register(specifier[, parentURL][, options])#

稳定性: 1.1 - 活跃开发。

  • specifier <string> 需要注册的定制钩子; 这应该与传递给 import() 的字符串相同,但如果它是相对的,则它是相对于 parentURL 解析的。
  • parentURL <string> 如果你想要相对于基本 URL(例如 import.meta.url)解析 specifier,你可以在此处传递该 URL。 默认值: 'data:'
  • options <Object>
  • 返回: <any> 返回 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);
}); 

定制钩子#

稳定性: 1.1 - 活跃开发。

启用#

可以通过注册导出一组钩子的文件来自定义模块解析和加载。 这可以使用 node:module 中的 register 方法来完成,你可以使用 --import 标志在应用代码之前运行该方法:

node --import ./register-hooks.js ./my-app.js 
// register-hooks.js
import { register } from 'node:module';

register('./hooks.mjs', import.meta.url);// 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 

其中 some-package 有一个 "exports" 字段,定义 /register 导出以映射到调用 register() 的文件,如以下 register-hooks.js 示例。

使用 --import 可确保在导入任何应用文件(包括应用的入口点)之前注册钩子。 或者,可以从入口点调用 register,但动态 import() 必须用于注册钩子后应运行的任何代码:

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');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)引用的任何模块运行。

最后,如果你只想在应用运行之前注册钩子,并且不想为此目的创建单独的文件,则可以将 data: URL 传递给 --import

node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("http-to-https", pathToFileURL("./"));' ./my-app.js 

链接#

可以多次调用 register

// entrypoint.mjs
import { register } from 'node:module';

register('./first.mjs', import.meta.url);
register('./second.mjs', import.meta.url);
await import('./my-app.mjs');// entrypoint.cjs
const { register } = require('node:module');
const { pathToFileURL } = require('node:url');

const parentURL = pathToFileURL(__filename);
register('./first.mjs', parentURL);
register('./second.mjs', parentURL);
import('./my-app.mjs');

在这个例子中,注册的钩子将形成链。 如果 first.mjssecond.mjs 都定义了 resolve 钩子,则两者都将按照它们注册的顺序被调用。 这同样适用于所有其他钩子。

注册的钩子也会影响 register 本身。 在此示例中,second.mjs 将根据 first.mjs 注册的钩子进行解析和加载。 这允许用非 JavaScript 语言编写钩子之类的事情,只要早期注册的加载器是转换为 JavaScript 的加载器即可。

无法从定义钩子的模块内调用 register 方法。

与模块定制钩子通信#

模块自定义钩子在专用线程上运行,与运行应用代码的主线程分开。 This means mutating global variables won't affect the other thread(s), and message channels must be used to communicate between the threads.

register 方法可用于将数据传递到 initialize 钩子。 传递到钩子的数据可能包括可传输对象,例如端口。

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],
});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 }) {
  // Receive data from `register`, return data to `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.
} 

钩子是链的一部分,即使该链仅由一个自定义(用户提供的)钩子和始终存在的默认钩子组成。 钩子函数嵌套: 每个都必须始终返回一个普通对象,并且链接是由于每个函数调用 next<hookName>() 而发生的,next<hookName>() 是对后续加载程序钩子的引用。

返回缺少必需属性的值的钩子会触发异常。 没有调用 next<hookName>() 和没有返回 shortCircuit: true 就返回的钩子也会触发异常。 这些错误有助于防止链中的意外中断。 从钩子返回 shortCircuit: true 表示该链有意在你的钩子处结束。

钩子在单独的线程中运行,与运行应用代码的主线程隔离。 这意味着它是一个不同的 realm。 hooks 线程随时可能被主线程终止,所以不要依赖异步操作(如 console.log)来完成。

initialize()#

稳定性: 1.1 - 活跃开发。

  • data <any> 数据来自 register(loader, import.meta.url, { data })
  • 返回: <any> 要返回给 register 的调用者的数据。

initialize hook 提供了一种定义自定义函数的方法,该函数在 hooks 模块初始化时在 hooks 线程中运行。 当 hooks 模块通过 register 注册时,就会进行初始化。

该钩子可以从 register 调用发送和接收数据,包括端口和其他可传输对象。 initialize 的返回值必须是:

  • undefined
  • 可以作为线程之间的消息发布的内容(例如 port.postMessage 的输入),
  • a Promise 解析为上述值之一。

模块定制代码:

// path-to-my-hooks.js

export async function initialize({ number, port }) {
  port.postMessage(`increment: ${number + 1}`);
  return 'ok';
} 

来电者代码:

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');
});

const result = register('./path-to-my-hooks.js', {
  parentURL: import.meta.url,
  data: { number: 1, port: port2 },
  transferList: [port2],
});

assert.strictEqual(result, 'ok');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');
});

const result = register('./path-to-my-hooks.js', {
  parentURL: pathToFileURL(__filename),
  data: { number: 1, port: port2 },
  transferList: [port2],
});

assert.strictEqual(result, 'ok');

resolve(specifier, context, nextResolve)#

稳定性: 1.2 - 候选版本

  • specifier <string>
  • context <Object>
    • conditions <string[]> 相关 package.json 的导出条件
    • importAssertions <Object> 一个对象,其键值对表示要导入的模块的断言
    • parentURL <string> | <undefined> 导入此模块的模块,如果这是 Node.js 入口点,则为未定义
  • nextResolve <Function> 链中后续的 resolve 钩子,或者用户提供的最后一个 resolve 钩子之后的 Node.js 默认 resolve 钩子
  • 返回: <Object> | <Promise>
    • format <string> | <null> | <undefined> 加载钩子的提示(可能会被忽略)'builtin' | 'commonjs' | 'json' | 'module' | 'wasm'
    • importAssertions <Object> | <undefined> 缓存模块时要使用的导入断言(可选;如果排除,将使用输入)
    • shortCircuit <undefined> | <boolean> 此钩子打算终止 resolve 钩子链的信号。 默认值: false
    • url <string> 此输入解析到的绝对 URL

警告 尽管支持返回 Promise 和异步函数,但对 resolve 的调用可能会阻塞主线程,从而影响性能。

resolve 钩子链负责告诉 Node.js 在哪里查找以及如何缓存给定的 import 语句或表达式,或 require 调用。 它可以选择返回一种格式(例如 'module')作为 load 钩子的提示。 如果指定了格式,load 钩子最终负责提供最终的 format 值(并且可以随意忽略 resolve 提供的提示); 如果 resolve 提供 format,则需要自定义 load 钩子,即使只是将值传递给 Node.js 默认的 load 钩子。

导入类型断言是缓存键的一部分,用于将加载的模块保存到内部模块缓存中。 如果模块应该使用与源代码中存在的断言不同的断言进行缓存,则 resolve 钩子负责返回 importAssertions 对象。

context 中的 conditions 属性是适用于此解析请求的 包导出条件 的条件数组。 它们可用于在别处查找条件映射或在调用默认解析逻辑时修改列表。

当前的 包导出条件 总是在传入钩子的 context.conditions 数组中。 为了保证在调用 defaultResolve 时默认的 Node.js 模块说明符解析行为,传递给它的 context.conditions 数组必须包括最初传递到 resolve 钩子的 context.conditions 数组的所有元素。

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

load(url, context, nextLoad)#

稳定性: 1.2 - 候选版本

load 钩子提供了一种方式来定义确定网址应如何解释、检索、以及解析的自定义方法。 它还负责验证导入断言。

format 的最终值必须是以下之一:

format描述load 返回的 source 的可接受类型
'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 具有非常不同的效果:

  • 当提供了 source 时,来自该模块的所有 require 调用都将由具有已注册 resolveload 钩子的 ESM 加载程序处理; 来自该模块的所有 require.resolve 调用都将由具有已注册 resolve 钩子的 ESM 加载程序处理; 只有 CommonJS API 的子集可用(例如,没有 require.extensions、没有 require.cache、没有 require.resolve.paths),并且 CommonJS 模块加载器上的猴子修补将不适用。
  • 如果 source 未定义或 null,它将由 CommonJS 模块加载器处理,并且 require/require.resolve 调用将不会通过注册的钩子。 nullish source 的这种行为是暂时的 — 以后将不再支持 nullish source

Node.js 内部 load 实现(即 load 链中最后一个钩子的 next 的值)在 format'commonjs' 时为 source 返回 null,以实现向后兼容性。 下面是一个选择使用非默认行为的示例钩子:

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;
} 

警告: ESM load 钩子和来自 CommonJS 模块的命名空间导出不兼容。 尝试将它们一起使用将导致导入的对象为空。 这可能会在未来得到解决。

这些类型都对应于 ECMAScript 中定义的类。

如果基于文本的格式(即 'json''module')的源值不是字符串,则使用 util.TextDecoder 将其转换为字符串。

load 钩子提供了一种定义自定义方法来检索已解析 URL 的源代码的方法。 这将允许加载器潜在地避免从磁盘读取文件。 它还可以用于将无法识别的格式映射到支持的格式,例如 yamlmodule

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

在更高级的场景中,这也可用于将不受支持的来源转换为受支持的来源(请参阅下面的 示例)。

globalPreload()#

稳定性: 1.0 - Early development

警告: 该钩子将在未来版本中删除。 改用 initialize。 当 hooks 模块具有 initialize 导出时,globalPreload 将被忽略。

有时可能需要在应用运行所在的同一全局作用域内运行一些代码。 此钩子允许返回在启动时作为宽松模式脚本运行的字符串。

类似于 CommonJS 封装器的工作方式,代码在隐式函数范围内运行。 唯一的参数是一个类似 require 的函数,可用于加载像 "fs" 这样的内置函数: getBuiltin(request: string)

如果代码需要更高级的 require 特性,则必须使用 module.createRequire() 构建自己的 require

export function globalPreload(context) {
  return `\
globalThis.someInjectedProperty = 42;
console.log('I just set some globals!');

const { createRequire } = getBuiltin('module');
const { cwd } = getBuiltin('process');

const require = createRequire(cwd() + '/<preload>');
// [...]
`;
} 

为预加载代码提供了另一个参数: port。 这可以作为钩子的参数以及钩子返回的源文本的内部。 此功能已移至 initialize 钩子。

必须小心地正确调用 port.ref()port.unref(),以防止进程处于无法正常关闭的状态。

/**
 * This example has the application context send a message to the hook
 * and sends the message back to the application context
 */
export function globalPreload({ port }) {
  port.onmessage = (evt) => {
    port.postMessage(evt.data);
  };
  return `\
    port.postMessage('console.log("I went to the hook and back");');
    port.onmessage = (evt) => {
      eval(evt.data);
    };
  `;
} 

示例#

各种模块自定义钩子可以一起使用来完成 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);
} 
// main.mjs
import { VERSION } from 'https://coffeescript.org/browser-compiler-modern/coffeescript.js';

console.log(VERSION); 

使用前面的 hooks 模块,运行 node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./https-hooks.mjs"));' ./main.mjs 会在 main.mjs 中的 URL 处打印每个模块的 CoffeeScript 的当前版本。

转换#

可以使用 load 钩子 将 Node.js 无法理解的格式的源代码转换为 JavaScript。

这比在运行 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);
    });
  // Ff package.json existed and contained a `type` field with a value, voila
  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, '..'));
} 
# 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}" 
# scream.coffee
export scream = (str) -> str.toUpperCase() 

使用前面的 hooks 模块,运行 node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./coffeescript-hooks.mjs"));' ./main.coffee 会导致 main.coffee 在其源代码从磁盘加载之后、Node.js 执行之前转换为 JavaScript; 对于通过任何加载文件的 import 语句引用的任何 .coffee.litcoffee.coffee.md 文件,依此类推。

导入映射#

前面的两个示例定义了 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);
} 

有了这些文件:

// main.js
import 'a-module'; 
// import-map.json
{
  "imports": {
    "a-module": "./some-module.js"
  }
} 
// some-module.js
console.log('some module!'); 

运行 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 支持#

稳定性: 1 - 实验

与源映射缓存交互的助手。 当启用源映射解析并且在模块的页脚中找到 源映射包含指令 时,将填充此缓存。

要启用源映射解析,则 Node.js 必须使用标志 --enable-source-maps 运行、或者通过设置 NODE_V8_COVERAGE=dir 启用代码覆盖率。

// module.mjs
// In an ECMAScript module
import { findSourceMap, SourceMap } from 'node:module';// module.cjs
// In a CommonJS module
const { findSourceMap, SourceMap } = require('node:module');

module.findSourceMap(path)#

path 是文件的解析路径,应为其获取相应的源映射。

类:module.SourceMap#

new SourceMap(payload[, { lineLengths }])#

创建新的 sourceMap 实例。

payload 是一个对象,其键与 源映射 v3 格式 匹配:

lineLengths 是生成代码中每行长度的可选数组。

sourceMap.payload#

用于构造 SourceMap 实例的有效负载的获取器。

sourceMap.findEntry(lineOffset, columnOffset)#
  • lineOffset <number> 生成的源中的零索引行号偏移量
  • columnOffset <number> 生成的源中的零索引列号偏移量
  • 返回: <Object>

给定生成的源文件中的行偏移量和列偏移量,如果找到,则返回表示原始文件中的 SourceMap 范围的对象,如果没有,则返回空对象。

返回的对象包含以下键:

  • generatedLine: <number> 生成的源中范围开始的行偏移量
  • generatedColumn: <number> 生成的源中范围开始的列偏移量
  • originalSource: <string> 原始源的文件名,如 SourceMap 中报告的那样
  • originalLine: <number> 原始源中范围开始的行偏移量
  • originalColumn: <number> 原始源中范围开始的列偏移量
  • name: <string>

返回的值表示 SourceMap 中显示的原始范围,基于零索引偏移量,而不是错误消息和 CallSite 对象中显示的 1 索引行号和列号。

要从错误堆栈和 CallSite 对象报告的行号和列号中获取相应的 1 索引行号和列号,请使用 sourceMap.findOrigin(lineNumber, columnNumber)

sourceMap.findOrigin(lineNumber, columnNumber)#
  • lineNumber <number> 生成的源中调用站点的 1 索引行号
  • columnOffset <number> 生成源中调用站点的 1 索引列号
  • 返回: <Object>

给定生成源中调用站点的 1 索引行号和列号,在原始源中查找相应的调用站点位置。

如果在任何源映射中都找不到提供的行号和列号,则返回空对象。 否则,返回的对象包含以下键:

  • name: <string> | <undefined> 源映射中范围的名称(如果提供)
  • fileName: <string> 原始源的文件名,如 SourceMap 中报告的那样
  • lineNumber: <number> 原始源中相应调用站点的 1 索引 lineNumber
  • columnNumber: <number> 原始源中相应调用站点的 1 索引列编号