当 importModuleDynamically 为 vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER 时
¥When importModuleDynamically
is vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER
vm.SourceTextModule
目前不支持此选项。
¥This option is currently not supported for vm.SourceTextModule
.
使用此选项,当在编译的代码中启动 import()
时,Node.js 将使用主上下文中的默认 ESM 加载器来加载请求的模块并将其返回到正在执行的代码。
¥With this option, when an import()
is initiated in the compiled code, Node.js
would use the default ESM loader from the main context to load the requested
module and return it to the code being executed.
这使得正在编译的代码可以访问 Node.js 内置模块,例如 fs
或 http
。如果代码在不同的上下文中执行,请注意从主上下文加载的模块创建的对象仍然来自主上下文,而不是新上下文中的 instanceof
内置类。
¥This gives access to Node.js built-in modules such as fs
or http
to the code being compiled. If the code is executed in a different context,
be aware that the objects created by modules loaded from the main context
are still from the main context and not instanceof
built-in classes in the
new context.
const { Script, constants } = require('node:vm');
const script = new Script(
'import("node:fs").then(({readFile}) => readFile instanceof Function)',
{ importModuleDynamically: constants.USE_MAIN_CONTEXT_DEFAULT_LOADER });
// false: URL loaded from the main context is not an instance of the Function
// class in the new context.
script.runInNewContext().then(console.log);
import { Script, constants } from 'node:vm';
const script = new Script(
'import("node:fs").then(({readFile}) => readFile instanceof Function)',
{ importModuleDynamically: constants.USE_MAIN_CONTEXT_DEFAULT_LOADER });
// false: URL loaded from the main context is not an instance of the Function
// class in the new context.
script.runInNewContext().then(console.log);
此选项还允许脚本或函数加载用户模块:
¥This option also allows the script or function to load user modules:
import { Script, constants } from 'node:vm';
import { resolve } from 'node:path';
import { writeFileSync } from 'node:fs';
// Write test.js and test.txt to the directory where the current script
// being run is located.
writeFileSync(resolve(import.meta.dirname, 'test.mjs'),
'export const filename = "./test.json";');
writeFileSync(resolve(import.meta.dirname, 'test.json'),
'{"hello": "world"}');
// Compile a script that loads test.mjs and then test.json
// as if the script is placed in the same directory.
const script = new Script(
`(async function() {
const { filename } = await import('./test.mjs');
return import(filename, { with: { type: 'json' } })
})();`,
{
filename: resolve(import.meta.dirname, 'test-with-default.js'),
importModuleDynamically: constants.USE_MAIN_CONTEXT_DEFAULT_LOADER,
});
// { default: { hello: 'world' } }
script.runInThisContext().then(console.log);
const { Script, constants } = require('node:vm');
const { resolve } = require('node:path');
const { writeFileSync } = require('node:fs');
// Write test.js and test.txt to the directory where the current script
// being run is located.
writeFileSync(resolve(__dirname, 'test.mjs'),
'export const filename = "./test.json";');
writeFileSync(resolve(__dirname, 'test.json'),
'{"hello": "world"}');
// Compile a script that loads test.mjs and then test.json
// as if the script is placed in the same directory.
const script = new Script(
`(async function() {
const { filename } = await import('./test.mjs');
return import(filename, { with: { type: 'json' } })
})();`,
{
filename: resolve(__dirname, 'test-with-default.js'),
importModuleDynamically: constants.USE_MAIN_CONTEXT_DEFAULT_LOADER,
});
// { default: { hello: 'world' } }
script.runInThisContext().then(console.log);
使用主上下文中的默认加载器加载用户模块有一些注意事项:
¥There are a few caveats with loading user modules using the default loader from the main context:
-
正在解析的模块将与传递给
vm.Script
或vm.compileFunction()
的filename
选项相关。该解析可以使用绝对路径或 URL 字符串的filename
。如果filename
是一个既不是绝对路径也不是 URL 的字符串,或者未定义,则解析将相对于进程的当前工作目录。在vm.createContext()
的情况下,解析始终相对于当前工作目录,因为仅当没有引用脚本或模块时才使用此选项。¥The module being resolved would be relative to the
filename
option passed tovm.Script
orvm.compileFunction()
. The resolution can work with afilename
that's either an absolute path or a URL string. Iffilename
is a string that's neither an absolute path or a URL, or if it's undefined, the resolution will be relative to the current working directory of the process. In the case ofvm.createContext()
, the resolution is always relative to the current working directory since this option is only used when there isn't a referrer script or module. -
对于解析为特定路径的任何给定
filename
,一旦进程设法从该路径加载特定模块,结果可能会被缓存,并且从同一路径加载同一模块的后续加载将返回相同的内容。如果filename
是一个 URL 字符串,那么如果它具有不同的搜索参数,则不会命中缓存。对于不是 URL 字符串的filename
,目前无法绕过缓存行为。¥For any given
filename
that resolves to a specific path, once the process manages to load a particular module from that path, the result may be cached, and subsequent load of the same module from the same path would return the same thing. If thefilename
is a URL string, the cache would not be hit if it has different search parameters. Forfilename
s that are not URL strings, there is currently no way to bypass the caching behavior.