diff --git a/doc/api/cli.md b/doc/api/cli.md index c9b8dc3b2b..8337a9aef5 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -97,13 +97,6 @@ added: v10.0.0 Enable experimental top-level `await` keyword support in REPL. -### `--experimental-vm-modules` - - -Enable experimental ES Module support in the `vm` module. - ### `--experimental-worker` - -> Stability: 1 - Experimental - -*This feature is only available with the `--experimental-vm-modules` command -flag enabled.* - -The `vm.SourceTextModule` class provides a low-level interface for using -ECMAScript modules in VM contexts. It is the counterpart of the `vm.Script` -class that closely mirrors [Source Text Module Record][]s as defined in the -ECMAScript specification. - -Unlike `vm.Script` however, every `vm.SourceTextModule` object is bound to a -context from its creation. Operations on `vm.SourceTextModule` objects are -intrinsically asynchronous, in contrast with the synchronous nature of -`vm.Script` objects. With the help of async functions, however, manipulating -`vm.SourceTextModule` objects is fairly straightforward. - -Using a `vm.SourceTextModule` object requires four distinct steps: -creation/parsing, linking, instantiation, and evaluation. These four steps are -illustrated in the following example. - -This implementation lies at a lower level than the [ECMAScript Module -loader][]. There is also currently no way to interact with the Loader, though -support is planned. - -```js -const vm = require('vm'); - -const contextifiedSandbox = vm.createContext({ secret: 42 }); - -(async () => { - // Step 1 - // - // Create a Module by constructing a new `vm.SourceTextModule` object. This - // parses the provided source text, throwing a `SyntaxError` if anything goes - // wrong. By default, a Module is created in the top context. But here, we - // specify `contextifiedSandbox` as the context this Module belongs to. - // - // Here, we attempt to obtain the default export from the module "foo", and - // put it into local binding "secret". - - const bar = new vm.SourceTextModule(` - import s from 'foo'; - s; - `, { context: contextifiedSandbox }); - - // Step 2 - // - // "Link" the imported dependencies of this Module to it. - // - // The provided linking callback (the "linker") accepts two arguments: the - // parent module (`bar` in this case) and the string that is the specifier of - // the imported module. The callback is expected to return a Module that - // corresponds to the provided specifier, with certain requirements documented - // in `module.link()`. - // - // If linking has not started for the returned Module, the same linker - // callback will be called on the returned Module. - // - // Even top-level Modules without dependencies must be explicitly linked. The - // callback provided would never be called, however. - // - // The link() method returns a Promise that will be resolved when all the - // Promises returned by the linker resolve. - // - // Note: This is a contrived example in that the linker function creates a new - // "foo" module every time it is called. In a full-fledged module system, a - // cache would probably be used to avoid duplicated modules. - - async function linker(specifier, referencingModule) { - if (specifier === 'foo') { - return new vm.SourceTextModule(` - // The "secret" variable refers to the global variable we added to - // "contextifiedSandbox" when creating the context. - export default secret; - `, { context: referencingModule.context }); - - // Using `contextifiedSandbox` instead of `referencingModule.context` - // here would work as well. - } - throw new Error(`Unable to resolve dependency: ${specifier}`); - } - await bar.link(linker); - - // Step 3 - // - // Instantiate the top-level Module. - // - // Only the top-level Module needs to be explicitly instantiated; its - // dependencies will be recursively instantiated by instantiate(). - - bar.instantiate(); - - // Step 4 - // - // Evaluate the Module. The evaluate() method returns a Promise with a single - // property "result" that contains the result of the very last statement - // executed in the Module. In the case of `bar`, it is `s;`, which refers to - // the default export of the `foo` module, the `secret` we set in the - // beginning to 42. - - const { result } = await bar.evaluate(); - - console.log(result); - // Prints 42. -})(); -``` - -### Constructor: new vm.SourceTextModule(code[, options]) - -* `code` {string} JavaScript Module code to parse -* `options` - * `url` {string} URL used in module resolution and stack traces. **Default:** - `'vm:module(i)'` where `i` is a context-specific ascending index. - * `context` {Object} The [contextified][] object as returned by the - `vm.createContext()` method, to compile and evaluate this `Module` in. - * `lineOffset` {integer} Specifies the line number offset that is displayed - in stack traces produced by this `Module`. - * `columnOffset` {integer} Specifies the column number offset that is - displayed in stack traces produced by this `Module`. - * `initializeImportMeta` {Function} Called during evaluation of this `Module` - to initialize the `import.meta`. This function has the signature `(meta, - module)`, where `meta` is the `import.meta` object in the `Module`, and - `module` is this `vm.SourceTextModule` object. - * `importModuleDynamically` {Function} Called during evaluation of this - module when `import()` is called. This function has the signature - `(specifier, module)` where `specifier` is the specifier passed to - `import()` and `module` is this `vm.SourceTextModule`. If this option is - not specified, calls to `import()` will reject with - [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`][]. This method can return a - [Module Namespace Object][], but returning a `vm.SourceTextModule` is - recommended in order to take advantage of error tracking, and to avoid - issues with namespaces that contain `then` function exports. - -Creates a new ES `Module` object. - -Properties assigned to the `import.meta` object that are objects may -allow the `Module` to access information outside the specified `context`, if the -object is created in the top level context. Use `vm.runInContext()` to create -objects in a specific context. - -```js -const vm = require('vm'); - -const contextifiedSandbox = vm.createContext({ secret: 42 }); - -(async () => { - const module = new vm.SourceTextModule( - 'Object.getPrototypeOf(import.meta.prop).secret = secret;', - { - initializeImportMeta(meta) { - // Note: this object is created in the top context. As such, - // Object.getPrototypeOf(import.meta.prop) points to the - // Object.prototype in the top context rather than that in - // the sandbox. - meta.prop = {}; - } - }); - // Since module has no dependencies, the linker function will never be called. - await module.link(() => {}); - module.instantiate(); - await module.evaluate(); - - // Now, Object.prototype.secret will be equal to 42. - // - // To fix this problem, replace - // meta.prop = {}; - // above with - // meta.prop = vm.runInContext('{}', contextifiedSandbox); -})(); -``` - -### module.dependencySpecifiers - -* {string[]} - -The specifiers of all dependencies of this module. The returned array is frozen -to disallow any changes to it. - -Corresponds to the `[[RequestedModules]]` field of -[Source Text Module Record][]s in the ECMAScript specification. - -### module.error - -* {any} - -If the `module.status` is `'errored'`, this property contains the exception -thrown by the module during evaluation. If the status is anything else, -accessing this property will result in a thrown exception. - -The value `undefined` cannot be used for cases where there is not a thrown -exception due to possible ambiguity with `throw undefined;`. - -Corresponds to the `[[EvaluationError]]` field of [Source Text Module Record][]s -in the ECMAScript specification. - -### module.evaluate([options]) - -* `options` {Object} - * `timeout` {number} Specifies the number of milliseconds to evaluate - before terminating execution. If execution is interrupted, an [`Error`][] - will be thrown. - * `breakOnSigint` {boolean} If `true`, the execution will be terminated when - `SIGINT` (Ctrl+C) is received. Existing handlers for the event that have - been attached via `process.on('SIGINT')` will be disabled during script - execution, but will continue to work after that. If execution is - interrupted, an [`Error`][] will be thrown. -* Returns: {Promise} - -Evaluate the module. - -This must be called after the module has been instantiated; otherwise it will -throw an error. It could be called also when the module has already been -evaluated, in which case it will do one of the following two things: - -- return `undefined` if the initial evaluation ended in success (`module.status` - is `'evaluated'`) -- rethrow the same exception the initial evaluation threw if the initial - evaluation ended in an error (`module.status` is `'errored'`) - -This method cannot be called while the module is being evaluated -(`module.status` is `'evaluating'`) to prevent infinite recursion. - -Corresponds to the [Evaluate() concrete method][] field of [Source Text Module -Record][]s in the ECMAScript specification. - -### module.instantiate() - -Instantiate the module. This must be called after linking has completed -(`linkingStatus` is `'linked'`); otherwise it will throw an error. It may also -throw an exception if one of the dependencies does not provide an export the -parent module requires. - -However, if this function succeeded, further calls to this function after the -initial instantiation will be no-ops, to be consistent with the ECMAScript -specification. - -Unlike other methods operating on `Module`, this function completes -synchronously and returns nothing. - -Corresponds to the [Instantiate() concrete method][] field of [Source Text -Module Record][]s in the ECMAScript specification. - -### module.link(linker) - -* `linker` {Function} -* Returns: {Promise} - -Link module dependencies. This method must be called before instantiation, and -can only be called once per module. - -Two parameters will be passed to the `linker` function: - -- `specifier` The specifier of the requested module: - - ```js - import foo from 'foo'; - // ^^^^^ the module specifier - ``` -- `referencingModule` The `Module` object `link()` is called on. - -The function is expected to return a `Module` object or a `Promise` that -eventually resolves to a `Module` object. The returned `Module` must satisfy the -following two invariants: - -- It must belong to the same context as the parent `Module`. -- Its `linkingStatus` must not be `'errored'`. - -If the returned `Module`'s `linkingStatus` is `'unlinked'`, this method will be -recursively called on the returned `Module` with the same provided `linker` -function. - -`link()` returns a `Promise` that will either get resolved when all linking -instances resolve to a valid `Module`, or rejected if the linker function either -throws an exception or returns an invalid `Module`. - -The linker function roughly corresponds to the implementation-defined -[HostResolveImportedModule][] abstract operation in the ECMAScript -specification, with a few key differences: - -- The linker function is allowed to be asynchronous while - [HostResolveImportedModule][] is synchronous. -- The linker function is executed during linking, a Node.js-specific stage - before instantiation, while [HostResolveImportedModule][] is called during - instantiation. - -The actual [HostResolveImportedModule][] implementation used during module -instantiation is one that returns the modules linked during linking. Since at -that point all modules would have been fully linked already, the -[HostResolveImportedModule][] implementation is fully synchronous per -specification. - -### module.linkingStatus - -* {string} - -The current linking status of `module`. It will be one of the following values: - -- `'unlinked'`: `module.link()` has not yet been called. -- `'linking'`: `module.link()` has been called, but not all Promises returned by - the linker function have been resolved yet. -- `'linked'`: `module.link()` has been called, and all its dependencies have - been successfully linked. -- `'errored'`: `module.link()` has been called, but at least one of its - dependencies failed to link, either because the callback returned a `Promise` - that is rejected, or because the `Module` the callback returned is invalid. - -### module.namespace - -* {Object} - -The namespace object of the module. This is only available after instantiation -(`module.instantiate()`) has completed. - -Corresponds to the [GetModuleNamespace][] abstract operation in the ECMAScript -specification. - -### module.status - -* {string} - -The current status of the module. Will be one of: - -- `'uninstantiated'`: The module is not instantiated. It may because of any of - the following reasons: - - - The module was just created. - - `module.instantiate()` has been called on this module, but it failed for - some reason. - - This status does not convey any information regarding if `module.link()` has - been called. See `module.linkingStatus` for that. - -- `'instantiating'`: The module is currently being instantiated through a - `module.instantiate()` call on itself or a parent module. - -- `'instantiated'`: The module has been instantiated successfully, but - `module.evaluate()` has not yet been called. - -- `'evaluating'`: The module is being evaluated through a `module.evaluate()` on - itself or a parent module. - -- `'evaluated'`: The module has been successfully evaluated. - -- `'errored'`: The module has been evaluated, but an exception was thrown. - -Other than `'errored'`, this status string corresponds to the specification's -[Source Text Module Record][]'s `[[Status]]` field. `'errored'` corresponds to -`'evaluated'` in the specification, but with `[[EvaluationError]]` set to a -value that is not `undefined`. - -### module.url - -* {string} - -The URL of the current module, as set in the constructor. - ## Class: vm.Script