启用


¥Enabling

模块解析和加载可以通过以下方式自定义:

¥Module resolution and loading can be customized by:

  1. 使用来自 node:moduleregister 方法注册导出一组异步钩子函数的文件,

    ¥Registering a file which exports a set of asynchronous hook functions, using the register method from node:module,

  2. 使用来自 node:moduleregisterHooks 方法注册一组同步钩子函数。

    ¥Registering a set of synchronous hook functions using the registerHooks method from node:module.

可以使用 --import--require 标志在运行应用代码之前注册钩子:

¥The hooks can be registered before the application code is run by using the --import or --require flag:

node --import ./register-hooks.js ./my-app.js
node --require ./register-hooks.js ./my-app.js 
// 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));
// 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 */ },
});

传递给 --import--require 的文件也可以是从依赖导出的:

¥The file passed to --import or --require can also be an export from a dependency:

node --import some-package/register ./my-app.js
node --require some-package/register ./my-app.js 

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

¥Where some-package has an "exports" field defining the /register export to map to a file that calls register(), like the following register-hooks.js example.

使用 --import--require 可确保在导入任何应用文件之前注册钩子,包括应用的入口点以及默认情况下的任何工作线程。

¥Using --import or --require ensures that the hooks are registered before any application files are imported, including the entry point of the application and for any worker threads by default as well.

或者,可以从入口点调用 register()registerHooks(),但对于在注册钩子后应运行的任何 ESM 代码,必须使用动态 import()

¥Alternatively, register() and registerHooks() can be called from the entry point, though dynamic import() must be used for any ESM code that should be run after the hooks are registered.

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

自定义钩子将针对注册后加载的任何模块以及它们通过 import 和内置 require 引用的模块运行。用户使用 module.createRequire() 创建的 require 函数只能由同步钩子自定义。

¥Customization hooks will run for any modules loaded later than the registration and the modules they reference via import and the built-in require. require function created by users using module.createRequire() can only be customized by the synchronous hooks.

在此示例中,我们正在注册 http-to-https 钩子,但它们仅适用于随后导入的模块 - 在本例中,my-app.js 及其通过 import 或 CommonJS 依赖中的内置 require 引用的任何内容。

¥In this example, we are registering the http-to-https hooks, but they will only be available for subsequently imported modules — in this case, my-app.js and anything it references via import or built-in require in CommonJS dependencies.

如果 import('./my-app.js') 是静态 import './my-app.js',则应用将在注册 http-to-https 钩子之前已加载。这是由于 ES 模块规范,其中静态导入首先从树的叶子进行评估,然后返回主干。my-app.js 内可以有静态导入,直到动态导入 my-app.js 后才会对其求值。

¥If the import('./my-app.js') had instead been a static import './my-app.js', the app would have already been loaded before the http-to-https hooks were registered. This due to the ES modules specification, where static imports are evaluated from the leaves of the tree first, then back to the trunk. There can be static imports within my-app.js, which will not be evaluated until my-app.js is dynamically imported.

如果使用同步钩子,则支持使用 createRequire() 创建的 importrequire 和用户 require

¥If synchronous hooks are used, both import, require and user require created using createRequire() are supported.

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

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

¥Finally, if all you want to do is register hooks before your app runs and you don't want to create a separate file for that purpose, you can pass a data: URL to --import:

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