启用#
模块的解析和加载可以通过以下方式进行自定义:
使用 node:module 中的 register 方法注册一个导出一组异步钩子函数的文件,
使用 node:module 中的 registerHooks 方法注册一组同步钩子函数。
钩子可以在应用程序代码运行之前通过使用 --import 或 --require 标志来注册:
node --import ./register-hooks.js ./my-app.js
node --require ./register-hooks.js ./my-app.js copy
// register-hooks.js
// This file can only be require()-ed if it doesn't contain top-level await.
// Use module.register() to register asynchronous hooks in a dedicated thread.
import { register } from 'node:module';
register('./hooks.mjs', import.meta.url);// register-hooks.js
const { register } = require('node:module');
const { pathToFileURL } = require('node:url');
// Use module.register() to register asynchronous hooks in a dedicated thread.
register('./hooks.mjs', pathToFileURL(__filename));copy
// Use module.registerHooks() to register synchronous hooks in the main thread.
import { registerHooks } from 'node:module';
registerHooks({
resolve(specifier, context, nextResolve) { /* implementation */ },
load(url, context, nextLoad) { /* implementation */ },
});// Use module.registerHooks() to register synchronous hooks in the main thread.
const { registerHooks } = require('node:module');
registerHooks({
resolve(specifier, context, nextResolve) { /* implementation */ },
load(url, context, nextLoad) { /* implementation */ },
});copy
传递给 --import 或 --require 的文件也可以是依赖项的导出:
node --import some-package/register ./my-app.js
node --require some-package/register ./my-app.js copy
其中 some-package 有一个 "exports" 字段,定义了 /register 导出,映射到一个调用 register() 的文件,如下面的 register-hooks.js 示例。
使用 --import 或 --require 可以确保钩子在任何应用程序文件被导入之前注册,包括应用程序的入口点,并且默认情况下也适用于任何工作线程。
或者,register() 和 registerHooks() 也可以从入口点调用,不过对于任何应该在钩子注册后运行的 ESM 代码,必须使用动态 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');copy
自定义钩子将对晚于注册加载的任何模块以及它们通过 import 和内置 require 引用的模块生效。用户使用 module.createRequire() 创建的 require 函数只能由同步钩子自定义。
在此示例中,我们注册了 `http-to-https` 钩子,但它们仅对后续导入的模块可用 —— 在本例中是 `my-app.js` 及其通过 `import` 或 CommonJS 依赖项中的内置 `require` 引用的任何内容。
如果 import('./my-app.js') 是一个静态的 import './my-app.js',那么应用程序将在 `http-to-https` 钩子注册*之前*就*已经*被加载了。这是由于 ES 模块规范,其中静态导入首先从树的叶子节点开始评估,然后回到主干。在 `my-app.js` *内部*可以有静态导入,这些静态导入直到 `my-app.js` 被动态导入时才会被评估。
如果使用同步钩子,则支持 import、require 和用户使用 createRequire() 创建的 require。
import { registerHooks, createRequire } from 'node:module';
registerHooks({ /* implementation of synchronous hooks */ });
const require = createRequire(import.meta.url);
// The synchronous hooks affect import, require() and user require() function
// created through createRequire().
await import('./my-app.js');
require('./my-app-2.js');const { register, registerHooks } = require('node:module');
const { pathToFileURL } = require('node:url');
registerHooks({ /* implementation of synchronous hooks */ });
const userRequire = createRequire(__filename);
// The synchronous hooks affect import, require() and user require() function
// created through createRequire().
import('./my-app.js');
require('./my-app-2.js');
userRequire('./my-app-3.js');copy
最后,如果你只想在应用程序运行前注册钩子,并且不想为此创建一个单独的文件,你可以将一个 `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 copy