异步 load 钩子中的注意事项
¥Caveat in the asynchronous load
hook
使用异步 load
钩子时,省略与为 'commonjs'
提供 source
的效果非常不同:
¥When using the asynchronous load
hook, omitting vs providing a source
for
'commonjs'
has very different effects:
-
当提供了
source
时,来自该模块的所有require
调用都将由具有已注册resolve
和load
钩子的 ESM 加载程序处理;来自该模块的所有require.resolve
调用都将由具有已注册resolve
钩子的 ESM 加载程序处理;只有 CommonJS API 的子集可用(例如,没有require.extensions
、没有require.cache
、没有require.resolve.paths
),并且 CommonJS 模块加载器上的猴子修补将不适用。¥When a
source
is provided, allrequire
calls from this module will be processed by the ESM loader with registeredresolve
andload
hooks; allrequire.resolve
calls from this module will be processed by the ESM loader with registeredresolve
hooks; only a subset of the CommonJS API will be available (e.g. norequire.extensions
, norequire.cache
, norequire.resolve.paths
) and monkey-patching on the CommonJS module loader will not apply. -
如果
source
未定义或null
,它将由 CommonJS 模块加载器处理,并且require
/require.resolve
调用将不会通过注册的钩子。nullishsource
的这种行为是暂时的 - 将来将不再支持 nullishsource
。¥If
source
is undefined ornull
, it will be handled by the CommonJS module loader andrequire
/require.resolve
calls will not go through the registered hooks. This behavior for nullishsource
is temporary — in the future, nullishsource
will not be supported.
这些警告不适用于同步 load
钩子,在这种情况下,自定义 CommonJS 模块和 require
/require.resolve
可用的完整 CommonJS API 集始终通过已注册的钩子。
¥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'
时,为 source
返回 null
,以实现向后兼容。下面是一个选择使用非默认行为的示例钩子:
¥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.
警告:异步
load
钩子和 CommonJS 模块的命名空间导出不兼容。尝试将它们一起使用将导致导入的对象为空。这可能会在未来得到解决。这不适用于同步load
钩子,在这种情况下可以照常使用导出。¥Warning: The asynchronous
load
hook and namespaced exports from CommonJS modules are incompatible. Attempting to use them together will result in an empty object from the import. This may be addressed in the future. This does not apply to the synchronousload
hook, in which case exports can be used as usual.
这些类型都对应于 ECMAScript 中定义的类。
¥These types all correspond to classes defined in ECMAScript.
-
特定的 <ArrayBuffer> 对象是 <SharedArrayBuffer>。
¥The specific <ArrayBuffer> object is a <SharedArrayBuffer>.
-
特定的 <TypedArray> 对象是 <Uint8Array>。
¥The specific <TypedArray> object is a <Uint8Array>.
如果基于文本的格式(即 'json'
、'module'
)的源值不是字符串,则使用 util.TextDecoder
将其转换为字符串。
¥If the source value of a text-based format (i.e., 'json'
, 'module'
)
is not a string, it is converted to a string using util.TextDecoder
.
load
钩子提供了一种定义自定义方法来检索已解析 URL 的源代码的方法。这将允许加载器潜在地避免从磁盘读取文件。它还可以用于将无法识别的格式映射到支持的格式,例如 yaml
到 module
。
¥The load
hook provides a way to define a custom method for retrieving the
source code of a resolved URL. This would allow a loader to potentially avoid
reading files from disk. It could also be used to map an unrecognized format to
a supported one, for example yaml
to module
.
// Asynchronous version accepted by module.register().
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);
}
// Synchronous version accepted by module.registerHooks().
function load(url, context, nextLoad) {
// Similar to the asynchronous load() above, since that one does not have
// any asynchronous logic.
}
在更高级的场景中,这也可用于将不受支持的来源转换为受支持的来源(请参阅下面的 示例)。
¥In a more advanced scenario, this can also be used to transform an unsupported source to a supported one (see Examples below).