Skip to content

Commit e0e7aa1

Browse files
aduh95danielleadams
authored andcommittedMar 16, 2021
doc: add top-level await syntax in vm.md
PR-URL: #37077 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 0d04b6c commit e0e7aa1

File tree

1 file changed

+115
-10
lines changed

1 file changed

+115
-10
lines changed
 

‎doc/api/vm.md

+115-10
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,78 @@ This implementation lies at a lower level than the [ECMAScript Module
408408
loader][]. There is also no way to interact with the Loader yet, though
409409
support is planned.
410410

411-
```js
411+
```mjs
412+
import vm from 'vm';
413+
414+
const contextifiedObject = vm.createContext({
415+
secret: 42,
416+
print: console.log,
417+
});
418+
419+
// Step 1
420+
//
421+
// Create a Module by constructing a new `vm.SourceTextModule` object. This
422+
// parses the provided source text, throwing a `SyntaxError` if anything goes
423+
// wrong. By default, a Module is created in the top context. But here, we
424+
// specify `contextifiedObject` as the context this Module belongs to.
425+
//
426+
// Here, we attempt to obtain the default export from the module "foo", and
427+
// put it into local binding "secret".
428+
429+
const bar = new vm.SourceTextModule(`
430+
import s from 'foo';
431+
s;
432+
print(s);
433+
`, { context: contextifiedObject });
434+
435+
// Step 2
436+
//
437+
// "Link" the imported dependencies of this Module to it.
438+
//
439+
// The provided linking callback (the "linker") accepts two arguments: the
440+
// parent module (`bar` in this case) and the string that is the specifier of
441+
// the imported module. The callback is expected to return a Module that
442+
// corresponds to the provided specifier, with certain requirements documented
443+
// in `module.link()`.
444+
//
445+
// If linking has not started for the returned Module, the same linker
446+
// callback will be called on the returned Module.
447+
//
448+
// Even top-level Modules without dependencies must be explicitly linked. The
449+
// callback provided would never be called, however.
450+
//
451+
// The link() method returns a Promise that will be resolved when all the
452+
// Promises returned by the linker resolve.
453+
//
454+
// Note: This is a contrived example in that the linker function creates a new
455+
// "foo" module every time it is called. In a full-fledged module system, a
456+
// cache would probably be used to avoid duplicated modules.
457+
458+
async function linker(specifier, referencingModule) {
459+
if (specifier === 'foo') {
460+
return new vm.SourceTextModule(`
461+
// The "secret" variable refers to the global variable we added to
462+
// "contextifiedObject" when creating the context.
463+
export default secret;
464+
`, { context: referencingModule.context });
465+
466+
// Using `contextifiedObject` instead of `referencingModule.context`
467+
// here would work as well.
468+
}
469+
throw new Error(`Unable to resolve dependency: ${specifier}`);
470+
}
471+
await bar.link(linker);
472+
473+
// Step 3
474+
//
475+
// Evaluate the Module. The evaluate() method returns a promise which will
476+
// resolve after the module has finished evaluating.
477+
478+
// Prints 42.
479+
await bar.evaluate();
480+
```
481+
482+
```cjs
412483
const vm = require('vm');
413484

414485
const contextifiedObject = vm.createContext({
@@ -542,8 +613,7 @@ The identifier of the current module, as set in the constructor.
542613

543614
* `linker` {Function}
544615
* `specifier` {string} The specifier of the requested module:
545-
<!-- eslint-skip -->
546-
```js
616+
```mjs
547617
import foo from 'foo';
548618
// ^^^^^ the module specifier
549619
```
@@ -673,11 +743,37 @@ Properties assigned to the `import.meta` object that are objects may
673743
allow the module to access information outside the specified `context`. Use
674744
`vm.runInContext()` to create objects in a specific context.
675745
676-
```js
677-
const vm = require('vm');
746+
```mjs
747+
import vm from 'vm';
678748
679749
const contextifiedObject = vm.createContext({ secret: 42 });
680750
751+
const module = new vm.SourceTextModule(
752+
'Object.getPrototypeOf(import.meta.prop).secret = secret;',
753+
{
754+
initializeImportMeta(meta) {
755+
// Note: this object is created in the top context. As such,
756+
// Object.getPrototypeOf(import.meta.prop) points to the
757+
// Object.prototype in the top context rather than that in
758+
// the contextified object.
759+
meta.prop = {};
760+
}
761+
});
762+
// Since module has no dependencies, the linker function will never be called.
763+
await module.link(() => {});
764+
await module.evaluate();
765+
766+
// Now, Object.prototype.secret will be equal to 42.
767+
//
768+
// To fix this problem, replace
769+
// meta.prop = {};
770+
// above with
771+
// meta.prop = vm.runInContext('{}', contextifiedObject);
772+
```
773+
774+
```cjs
775+
const vm = require('vm');
776+
const contextifiedObject = vm.createContext({ secret: 42 });
681777
(async () => {
682778
const module = new vm.SourceTextModule(
683779
'Object.getPrototypeOf(import.meta.prop).secret = secret;',
@@ -693,7 +789,6 @@ const contextifiedObject = vm.createContext({ secret: 42 });
693789
// Since module has no dependencies, the linker function will never be called.
694790
await module.link(() => {});
695791
await module.evaluate();
696-
697792
// Now, Object.prototype.secret will be equal to 42.
698793
//
699794
// To fix this problem, replace
@@ -794,17 +889,27 @@ This method is used after the module is linked to set the values of exports. If
794889
it is called before the module is linked, an [`ERR_VM_MODULE_STATUS`][] error
795890
will be thrown.
796891

797-
```js
798-
const vm = require('vm');
892+
```mjs
893+
import vm from 'vm';
799894
895+
const m = new vm.SyntheticModule(['x'], () => {
896+
m.setExport('x', 1);
897+
});
898+
899+
await m.link(() => {});
900+
await m.evaluate();
901+
902+
assert.strictEqual(m.namespace.x, 1);
903+
```
904+
905+
```cjs
906+
const vm = require('vm');
800907
(async () => {
801908
const m = new vm.SyntheticModule(['x'], () => {
802909
m.setExport('x', 1);
803910
});
804-
805911
await m.link(() => {});
806912
await m.evaluate();
807-
808913
assert.strictEqual(m.namespace.x, 1);
809914
})();
810915
```

0 commit comments

Comments
 (0)
Please sign in to comment.