异步 load(url, context, nextLoad)


🌐 Asynchronous load(url, context, nextLoad)

  • url <string> resolve 链返回的 URL

  • context <Object>

    • conditions <string[]> 相关 package.json 的导出条件
    • format <string> | <null> | <undefined> resolve 钩子链可选择提供的格式。这可以是任何字符串值作为输入;输入值不需要符合下文描述的可接受返回值列表。
    • importAttributes <Object>
  • nextLoad <Function> 链中的后续 load 钩子,或最后一个用户提供的 load 钩子之后的 Node.js 默认 load 钩子

    • url <string>

    • context <Object> | <undefined> 如果省略,将提供默认值。如果提供,将与默认值合并,并优先使用提供的属性。在默认 nextLoad 中,如果 url 指向的模块没有明确的模块类型信息,则 context.format 是必需的。

  • 返回:<Promise> 异步版本接受一个包含以下属性的对象,或者一个将解析为此类对象的 Promise

警告:异步 load 钩子与来自 CommonJS 模块的命名空间导出不兼容。尝试将它们一起使用将导致导入结果为空对象。未来可能会解决此问题。这不适用于同步 load 钩子,在这种情况下可以像平常一样使用导出。

异步版本的工作方式与同步版本类似,但在使用异步 load 钩子时,省略与提供 'commonjs'source 会产生非常不同的效果:

🌐 The asynchronous version works similarly to the synchronous version, though when using the asynchronous load hook, omitting vs providing a source for 'commonjs' has very different effects:

  • 当提供 source 时,该模块中的所有 require 调用将由 ESM 加载器处理,并使用已注册的 resolveload 钩子;该模块中的所有 require.resolve 调用将由 ESM 加载器处理,并使用已注册的 resolve 钩子;只有部分 CommonJS API 可用(例如没有 require.extensions、没有 require.cache、没有 require.resolve.paths),对 CommonJS 模块加载器的猴子补丁将不生效。
  • 如果 source 是未定义或 null,它将由 CommonJS 模块加载器处理,并且 require/require.resolve 调用不会经过注册的钩子。对于 null 值的 source,这种行为是暂时的——将来将不再支持 null 值的 source

这些注意事项不适用于同步的 load 钩子,在这种情况下,自定义 CommonJS 模块可以使用完整的 CommonJS API 集,require/require.resolve 始终会通过已注册的钩子。

🌐 These caveats do not apply to the synchronous load hook, in which case the complete set of CommonJS APIs available to the customized CommonJS modules, and require/require.resolve always go through the registered hooks.

Node.js 内部的异步 load 实现,即 load 链中最后一个钩子的 next 值,当 format'commonjs' 时,会为了向后兼容而返回 null 作为 source。下面是一个示例钩子,它将选择使用非默认行为:

🌐 The Node.js internal asynchronous load implementation, which is the value of next for the last hook in the load chain, returns null for source when format is 'commonjs' for backward compatibility. Here is an example hook that would opt-in to using the non-default behavior:

import { readFile } from 'node:fs/promises';

// Asynchronous version accepted by module.register(). This fix is not needed
// for the synchronous version accepted by module.registerHooks().
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;
} 

这同样不适用于同步的 load 钩子,在这种情况下,返回的 source 包含由下一个钩子加载的源代码,无论模块格式如何。

🌐 This doesn't apply to the synchronous load hook either, in which case the source returned contains source code loaded by the next hook, regardless of module format.