VM (exécution de JavaScript)
[Stable : 2 - Stable]
Stable : 2 Stability : 2 - Stable
Code source : lib/vm.js
Le module node:vm
permet de compiler et d'exécuter du code dans des contextes de machine virtuelle V8.
Le module node:vm
n'est pas un mécanisme de sécurité. Ne l'utilisez pas pour exécuter du code non fiable.
Le code JavaScript peut être compilé et exécuté immédiatement ou compilé, enregistré et exécuté ultérieurement.
Un cas d'utilisation courant consiste à exécuter le code dans un contexte V8 différent. Cela signifie que le code invoqué possède un objet global différent de celui du code appelant.
On peut fournir le contexte en contextualisant un objet. Le code invoqué traite toute propriété du contexte comme une variable globale. Toute modification des variables globales causée par le code invoqué se reflète dans l'objet contexte.
const vm = require('node:vm')
const x = 1
const context = { x: 2 }
vm.createContext(context) // Contextualiser l'objet.
const code = 'x += 40; var y = 17;'
// `x` et `y` sont des variables globales dans le contexte.
// Initialement, x a la valeur 2 car c'est la valeur de context.x.
vm.runInContext(code, context)
console.log(context.x) // 42
console.log(context.y) // 17
console.log(x) // 1; y n'est pas défini.
Classe : vm.Script
Ajouté dans : v0.3.1
Les instances de la classe vm.Script
contiennent des scripts précompilés qui peuvent être exécutés dans des contextes spécifiques.
new vm.Script(code[, options])
[Historique]
Version | Modifications |
---|---|
v21.7.0, v20.12.0 | Ajout de la prise en charge de vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Ajout de la prise en charge des attributs d'importation au paramètre importModuleDynamically . |
v10.6.0 | L'option produceCachedData est dépréciée au profit de script.createCachedData() . |
v5.7.0 | Les options cachedData et produceCachedData sont désormais prises en charge. |
v0.3.1 | Ajouté dans : v0.3.1 |
code
<string> Le code JavaScript à compiler.options
<Object> | <string>filename
<string> Spécifie le nom de fichier utilisé dans les traces de pile produites par ce script. Valeur par défaut :'evalmachine.<anonymous>'
.lineOffset
<number> Spécifie le décalage du numéro de ligne qui est affiché dans les traces de pile produites par ce script. Valeur par défaut :0
.columnOffset
<number> Spécifie le décalage du numéro de colonne de la première ligne qui est affiché dans les traces de pile produites par ce script. Valeur par défaut :0
.cachedData
<Buffer> | <TypedArray> | <DataView> Fournit unBuffer
ou unTypedArray
, ou unDataView
optionnel avec les données du cache de code de V8 pour la source fournie. Lorsqu'il est fourni, la valeurcachedDataRejected
sera définie surtrue
oufalse
en fonction de l'acceptation des données par V8.produceCachedData
<boolean> Lorsque la valeur esttrue
et qu'aucune donnéecachedData
n'est présente, V8 tentera de produire des données de cache de code pourcode
. En cas de succès, unBuffer
contenant les données du cache de code de V8 sera produit et stocké dans la propriétécachedData
de l'instancevm.Script
renvoyée. La valeurcachedDataProduced
sera définie surtrue
oufalse
selon que les données du cache de code sont produites avec succès ou non. Cette option est dépréciée au profit descript.createCachedData()
. Valeur par défaut :false
.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Utilisé pour spécifier comment les modules doivent être chargés lors de l'évaluation de ce script lorsqueimport()
est appelé. Cette option fait partie de l'API expérimentale des modules. Nous ne recommandons pas de l'utiliser en environnement de production. Pour plus d'informations, consultez Prise en charge deimport()
dynamique dans les API de compilation.
Si options
est une chaîne de caractères, elle spécifie le nom du fichier.
La création d'un nouvel objet vm.Script
compile code
mais ne l'exécute pas. Le vm.Script
compilé peut être exécuté ultérieurement plusieurs fois. Le code
n'est lié à aucun objet global ; il est plutôt lié avant chaque exécution, uniquement pour cette exécution.
script.cachedDataRejected
Ajouté dans : v5.7.0
Lorsque cachedData
est fourni pour créer le vm.Script
, cette valeur sera définie sur true
ou false
selon l'acceptation des données par V8. Sinon, la valeur est undefined
.
script.createCachedData()
Ajouté dans : v10.6.0
- Retourne : <Buffer>
Crée un cache de code qui peut être utilisé avec l'option cachedData
du constructeur Script
. Retourne un Buffer
. Cette méthode peut être appelée à tout moment et un nombre quelconque de fois.
Le cache de code du Script
ne contient aucun état observable JavaScript. Le cache de code peut être sauvegardé en toute sécurité avec la source du script et utilisé pour construire plusieurs fois de nouvelles instances Script
.
Les fonctions dans la source Script
peuvent être marquées comme compilées paresseusement et elles ne sont pas compilées lors de la construction du Script
. Ces fonctions seront compilées lors de leur premier appel. Le cache de code sérialise les métadonnées que V8 connaît actuellement sur le Script
qu'il peut utiliser pour accélérer les compilations futures.
const script = new vm.Script(`
function add(a, b) {
return a + b;
}
const x = add(1, 2);
`)
const cacheWithoutAdd = script.createCachedData()
// Dans `cacheWithoutAdd`, la fonction `add()` est marquée pour une compilation complète
// lors de son invocation.
script.runInThisContext()
const cacheWithAdd = script.createCachedData()
// `cacheWithAdd` contient la fonction `add()` entièrement compilée.
script.runInContext(contextifiedObject[, options])
[Historique]
Version | Modifications |
---|---|
v6.3.0 | L'option breakOnSigint est désormais prise en charge. |
v0.3.1 | Ajouté dans : v0.3.1 |
contextifiedObject
<Object> Un objet contextified tel que retourné par la méthodevm.createContext()
.options
<Object>displayErrors
<boolean> Lorsquetrue
, si une erreurError
se produit lors de la compilation ducode
, la ligne de code provoquant l'erreur est attachée à la trace de la pile. Par défaut :true
.timeout
<integer> Spécifie le nombre de millisecondes pour exécutercode
avant de terminer l'exécution. Si l'exécution est terminée, une erreurError
sera levée. Cette valeur doit être un entier strictement positif.breakOnSigint
<boolean> Sitrue
, la réception deSIGINT
(+) mettra fin à l'exécution et lèvera une erreurError
. Les gestionnaires existants de l'événement qui ont été attachés viaprocess.on('SIGINT')
sont désactivés pendant l'exécution du script, mais continuent de fonctionner après cela. Par défaut :false
.
Retourne : <any> le résultat de la toute dernière instruction exécutée dans le script.
Exécute le code compilé contenu par l'objet vm.Script
dans le contextifiedObject
donné et retourne le résultat. L'exécution du code n'a pas accès à la portée locale.
L'exemple suivant compile du code qui incrémente une variable globale, définit la valeur d'une autre variable globale, puis exécute le code plusieurs fois. Les variables globales sont contenues dans l'objet context
.
const vm = require('node:vm')
const context = {
animal: 'cat',
count: 2,
}
const script = new vm.Script('count += 1; name = "kitty";')
vm.createContext(context)
for (let i = 0; i < 10; ++i) {
script.runInContext(context)
}
console.log(context)
// Affiche : { animal: 'cat', count: 12, name: 'kitty' }
L'utilisation des options timeout
ou breakOnSigint
entraînera le démarrage de nouvelles boucles d'événements et de threads correspondants, qui ont des frais généraux de performance non nuls.
script.runInNewContext([contextObject[, options]])
[Historique]
Version | Modifications |
---|---|
v22.8.0, v20.18.0 | L'argument contextObject accepte désormais vm.constants.DONT_CONTEXTIFY . |
v14.6.0 | L'option microtaskMode est désormais prise en charge. |
v10.0.0 | L'option contextCodeGeneration est désormais prise en charge. |
v6.3.0 | L'option breakOnSigint est désormais prise en charge. |
v0.3.1 | Ajouté dans : v0.3.1 |
contextObject
<Objet> | <vm.constants.DONT_CONTEXTIFY> | <indéfini> Soitvm.constants.DONT_CONTEXTIFY
ou un objet qui sera contextualisé. Siindéfini
, un objet contextualisé vide sera créé pour la compatibilité descendante.options
<Objet>displayErrors
<booléen> Lorsqu'il est défini surtrue
, si une erreurError
se produit lors de la compilation ducode
, la ligne de code à l'origine de l'erreur est jointe à la trace de la pile. Valeur par défaut :true
.timeout
<entier> Spécifie le nombre de millisecondes pendant lesquelles exécutercode
avant d'arrêter l'exécution. Si l'exécution est interrompue, une erreurError
sera levée. Cette valeur doit être un entier strictement positif.breakOnSigint
<booléen> Sitrue
, la réception deSIGINT
(+) interrompra l'exécution et lèvera une erreurError
. Les gestionnaires existants de l'événement qui ont été attachés viaprocess.on('SIGINT')
sont désactivés pendant l'exécution du script, mais continuent de fonctionner après cela. Valeur par défaut :false
.contextName
<chaîne de caractères> Nom lisible par l'homme du contexte nouvellement créé. Valeur par défaut :'VM Context i'
, oùi
est un index numérique croissant du contexte créé.contextOrigin
<chaîne de caractères> Origine correspondant au contexte nouvellement créé à des fins d'affichage. L'origine doit être formatée comme une URL, mais avec uniquement le schéma, l'hôte et le port (si nécessaire), comme la valeur de la propriétéurl.origin
d'un objetURL
. Plus précisément, cette chaîne doit omettre la barre oblique finale, car elle désigne un chemin. Valeur par défaut :''
.contextCodeGeneration
<Objet>strings
<booléen> S'il est défini sur false, tous les appels àeval
ou aux constructeurs de fonctions (Function
,GeneratorFunction
, etc.) lèveront une erreurEvalError
. Valeur par défaut :true
.wasm
<booléen> S'il est défini sur false, toute tentative de compilation d'un module WebAssembly lèvera une erreurWebAssembly.CompileError
. Valeur par défaut :true
.microtaskMode
<chaîne de caractères> S'il est défini surafterEvaluate
, les microtâches (tâches planifiées via lesPromise
et lesasync function
) seront exécutées immédiatement après l'exécution du script. Elles sont incluses dans les portéestimeout
etbreakOnSigint
dans ce cas.
Retourne : <quelconque> le résultat de la toute dernière instruction exécutée dans le script.
Cette méthode est un raccourci vers script.runInContext(vm.createContext(options), options)
. Elle fait plusieurs choses à la fois :
L'exemple suivant compile du code qui définit une variable globale, puis exécute le code plusieurs fois dans différents contextes. Les globales sont définies sur et contenues dans chaque context
individuel.
const vm = require('node:vm')
const script = new vm.Script('globalVar = "set"')
const contexts = [{}, {}, {}]
contexts.forEach(context => {
script.runInNewContext(context)
})
console.log(contexts)
// Affiche : [{ globalVar: 'set' }, { globalVar: 'set' }, { globalVar: 'set' }]
// Cela lèverait une erreur si le contexte est créé à partir d'un objet contextualisé.
// vm.constants.DONT_CONTEXTIFY permet de créer des contextes avec des objets globaux ordinaires
// qui peuvent être gelés.
const freezeScript = new vm.Script('Object.freeze(globalThis); globalThis;')
const frozenContext = freezeScript.runInNewContext(vm.constants.DONT_CONTEXTIFY)
script.runInThisContext([options])
[Historique]
Version | Modifications |
---|---|
v6.3.0 | L'option breakOnSigint est maintenant prise en charge. |
v0.3.1 | Ajouté dans : v0.3.1 |
options
<Objet>displayErrors
<booléen> Lorsquetrue
, si une erreurError
se produit lors de la compilation ducode
, la ligne de code provoquant l'erreur est attachée à la trace de la pile. Valeur par défaut :true
.timeout
<entier> Spécifie le nombre de millisecondes pour exécutercode
avant d'arrêter l'exécution. Si l'exécution est interrompue, une erreurError
sera levée. Cette valeur doit être un entier strictement positif.breakOnSigint
<booléen> Sitrue
, la réception deSIGINT
(+) mettra fin à l'exécution et lèvera une erreurError
. Les gestionnaires existants de l'événement qui ont été attachés viaprocess.on('SIGINT')
sont désactivés pendant l'exécution du script, mais continuent de fonctionner après cela. Valeur par défaut :false
.
Retourne : <quelconque> le résultat de la toute dernière instruction exécutée dans le script.
Exécute le code compilé contenu par vm.Script
dans le contexte de l'objet global
actuel. Le code en cours d'exécution n'a pas accès à la portée locale, mais a accès à l'objet global
actuel.
L'exemple suivant compile du code qui incrémente une variable global
, puis exécute ce code plusieurs fois :
const vm = require('node:vm')
global.globalVar = 0
const script = new vm.Script('globalVar += 1', { filename: 'myfile.vm' })
for (let i = 0; i < 1000; ++i) {
script.runInThisContext()
}
console.log(globalVar)
// 1000
script.sourceMapURL
Ajouté dans : v19.1.0, v18.13.0
Lorsque le script est compilé à partir d’une source contenant un commentaire magique de mappage source, cette propriété sera définie sur l’URL de la mappage source.
import vm from 'node:vm'
const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`)
console.log(script.sourceMapURL)
// Affiche : sourcemap.json
const vm = require('node:vm')
const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`)
console.log(script.sourceMapURL)
// Affiche : sourcemap.json
Classe : vm.Module
Ajouté dans : v13.0.0, v12.16.0
[Stable : 1 - Expérimental]
Stable : 1 Stabilité : 1 - Expérimental
Cette fonctionnalité est uniquement disponible avec l’indicateur de commande --experimental-vm-modules
activé.
La classe vm.Module
fournit une interface de bas niveau pour l’utilisation de modules ECMAScript dans des contextes VM. C’est la contrepartie de la classe vm.Script
qui reflète étroitement les enregistrements de modules tels que définis dans la spécification ECMAScript.
Contrairement à vm.Script
cependant, chaque objet vm.Module
est lié à un contexte dès sa création. Les opérations sur les objets vm.Module
sont intrinsèquement asynchrones, contrairement à la nature synchrone des objets vm.Script
. L’utilisation de fonctions « async » peut aider à manipuler les objets vm.Module
.
L’utilisation d’un objet vm.Module
nécessite trois étapes distinctes : création/analyse, liaison et évaluation. Ces trois étapes sont illustrées dans l’exemple suivant.
Cette implémentation se situe à un niveau inférieur au chargeur de module ECMAScript. Il n’y a pas non plus de moyen d’interagir avec le chargeur pour le moment, bien que la prise en charge soit prévue.
import vm from 'node:vm'
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
})
// Étape 1
//
// Créer un module en construisant un nouvel objet `vm.SourceTextModule`. Cela
// analyse le texte source fourni, en lançant une `SyntaxError` si quelque chose ne va pas.
// Par défaut, un module est créé dans le contexte supérieur. Mais ici, nous
// spécifions `contextifiedObject` comme contexte auquel appartient ce module.
//
// Ici, nous essayons d’obtenir l’exportation par défaut du module « foo », et
// de le mettre dans la liaison locale « secret ».
const bar = new vm.SourceTextModule(
`
import s from 'foo';
s;
print(s);
`,
{ context: contextifiedObject }
)
// Étape 2
//
// « Lier » les dépendances importées de ce module à celui-ci.
//
// Le rappel de liaison fourni (le « liaiseur ») accepte deux arguments : le
// module parent (`bar` dans ce cas) et la chaîne qui est le spécificateur du
// module importé. Le rappel est censé renvoyer un module qui
// correspond au spécificateur fourni, avec certaines exigences documentées
// dans `module.link()`.
//
// Si la liaison n’a pas commencé pour le module renvoyé, le même rappel de liaison
// sera appelé sur le module renvoyé.
//
// Même les modules de niveau supérieur sans dépendances doivent être explicitement liés. Le
// rappel fourni ne serait jamais appelé, cependant.
//
// La méthode link() renvoie une Promise qui sera résolue lorsque toutes les
// Promises renvoyées par le lieur seront résolues.
//
// Remarque : Il s’agit d’un exemple artificiel dans la mesure où la fonction lieur crée un nouveau
// module « foo » à chaque fois qu’elle est appelée. Dans un système de modules complet, un
// cache serait probablement utilisé pour éviter les modules dupliqués.
async function linker(specifier, referencingModule) {
if (specifier === 'foo') {
return new vm.SourceTextModule(
`
// La variable « secret » fait référence à la variable globale que nous avons ajoutée à
// « contextifiedObject » lors de la création du contexte.
export default secret;
`,
{ context: referencingModule.context }
)
// L’utilisation de `contextifiedObject` au lieu de `referencingModule.context`
// ici fonctionnerait également.
}
throw new Error(`Impossible de résoudre la dépendance : ${specifier}`)
}
await bar.link(linker)
// Étape 3
//
// Évaluer le module. La méthode evaluate() renvoie une promesse qui sera
// résolue une fois que le module aura terminé son évaluation.
// Affiche 42.
await bar.evaluate()
const vm = require('node:vm')
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
})
;(async () => {
// Étape 1
//
// Créer un module en construisant un nouvel objet `vm.SourceTextModule`. Cela
// analyse le texte source fourni, en lançant une `SyntaxError` si quelque chose ne va pas.
// Par défaut, un module est créé dans le contexte supérieur. Mais ici, nous
// spécifions `contextifiedObject` comme contexte auquel appartient ce module.
//
// Ici, nous essayons d’obtenir l’exportation par défaut du module « foo », et
// de le mettre dans la liaison locale « secret ».
const bar = new vm.SourceTextModule(
`
import s from 'foo';
s;
print(s);
`,
{ context: contextifiedObject }
)
// Étape 2
//
// « Lier » les dépendances importées de ce module à celui-ci.
//
// Le rappel de liaison fourni (le « liaiseur ») accepte deux arguments : le
// module parent (`bar` dans ce cas) et la chaîne qui est le spécificateur du
// module importé. Le rappel est censé renvoyer un module qui
// correspond au spécificateur fourni, avec certaines exigences documentées
// dans `module.link()`.
//
// Si la liaison n’a pas commencé pour le module renvoyé, le même rappel de liaison
// sera appelé sur le module renvoyé.
//
// Même les modules de niveau supérieur sans dépendances doivent être explicitement liés. Le
// rappel fourni ne serait jamais appelé, cependant.
//
// La méthode link() renvoie une Promise qui sera résolue lorsque toutes les
// Promises renvoyées par le lieur seront résolues.
//
// Remarque : Il s’agit d’un exemple artificiel dans la mesure où la fonction lieur crée un nouveau
// module « foo » à chaque fois qu’elle est appelée. Dans un système de modules complet, un
// cache serait probablement utilisé pour éviter les modules dupliqués.
async function linker(specifier, referencingModule) {
if (specifier === 'foo') {
return new vm.SourceTextModule(
`
// La variable « secret » fait référence à la variable globale que nous avons ajoutée à
// « contextifiedObject » lors de la création du contexte.
export default secret;
`,
{ context: referencingModule.context }
)
// L’utilisation de `contextifiedObject` au lieu de `referencingModule.context`
// ici fonctionnerait également.
}
throw new Error(`Impossible de résoudre la dépendance : ${specifier}`)
}
await bar.link(linker)
// Étape 3
//
// Évaluer le module. La méthode evaluate() renvoie une promesse qui sera
// résolue une fois que le module aura terminé son évaluation.
// Affiche 42.
await bar.evaluate()
})()
module.dependencySpecifiers
Les spécificateurs de toutes les dépendances de ce module. Le tableau renvoyé est figé pour interdire toute modification.
Correspond au champ [[RequestedModules]]
des enregistrements de modules cycliques dans la spécification ECMAScript.
module.error
Si le module.status
est 'errored'
, cette propriété contient l'exception levée par le module pendant l'évaluation. Si le statut est autre chose, l'accès à cette propriété entraînera une exception levée.
La valeur undefined
ne peut pas être utilisée pour les cas où il n'y a pas d'exception levée en raison d'une ambiguïté possible avec throw undefined;
.
Correspond au champ [[EvaluationError]]
des enregistrements de modules cycliques dans la spécification ECMAScript.
module.evaluate([options])
options
<Object>timeout
<integer> Spécifie le nombre de millisecondes à évaluer avant de terminer l'exécution. Si l'exécution est interrompue, uneError
sera levée. Cette valeur doit être un entier strictement positif.breakOnSigint
<boolean> Sitrue
, la réception deSIGINT
(+) mettra fin à l'exécution et lèvera uneError
. Les gestionnaires existants de l'événement qui ont été attachés viaprocess.on('SIGINT')
sont désactivés pendant l'exécution du script, mais continuent à fonctionner après cela. Défaut :false
.
Retourne : <Promise> Restitue
undefined
en cas de succès.
Évaluer le module.
Cela doit être appelé après que le module a été lié ; sinon, il sera rejeté. Il pourrait également être appelé lorsque le module a déjà été évalué, auquel cas il ne fera rien si l'évaluation initiale s'est terminée avec succès (module.status
est 'evaluated'
) ou il relancera l'exception résultant de l'évaluation initiale (module.status
est 'errored'
).
Cette méthode ne peut pas être appelée pendant l'évaluation du module (module.status
est 'evaluating'
).
Correspond à la méthode concrète Evaluate() des enregistrements de modules cycliques dans la spécification ECMAScript.
module.identifier
L'identifiant du module courant, tel que défini dans le constructeur.
module.link(linker)
[Historique]
Version | Modifications |
---|---|
v21.1.0, v20.10.0, v18.19.0 | L'option extra.assert est renommée extra.attributes . L'ancien nom est toujours fourni pour la compatibilité descendante. |
linker
<Function>specifier
<string> Le spécificateur du module demandé :referencingModule
<vm.Module> L'objetModule
sur lequellink()
est appelé.extra
<Object>attributes
<Object> Les données de l'attribut : Conformément à ECMA-262, les hôtes doivent déclencher une erreur si un attribut non pris en charge est présent.assert
<Object> Alias pourextra.attributes
.Retourne : <vm.Module> | <Promise>
Retourne : <Promise>
Lier les dépendances des modules. Cette méthode doit être appelée avant l'évaluation et ne peut être appelée qu'une seule fois par module.
La fonction est censée retourner un objet Module
ou une Promise
qui finit par résoudre un objet Module
. Le Module
retourné doit satisfaire les deux invariants suivants :
- Il doit appartenir au même contexte que le
Module
parent. - Son
status
ne doit pas être'errored'
.
Si le status
du Module
retourné est 'unlinked'
, cette méthode sera appelée récursivement sur le Module
retourné avec la même fonction linker
fournie.
link()
retourne une Promise
qui sera soit résolue lorsque toutes les instances de liaison résolvent un Module
valide, soit rejetée si la fonction linker déclenche une exception ou retourne un Module
invalide.
La fonction linker correspond approximativement à l'opération abstraite HostResolveImportedModule définie par l'implémentation dans la spécification ECMAScript, avec quelques différences clés :
- La fonction linker peut être asynchrone tandis que HostResolveImportedModule est synchrone.
L'implémentation réelle de HostResolveImportedModule utilisée lors de la liaison des modules est celle qui retourne les modules liés pendant la liaison. À ce stade, tous les modules ayant déjà été entièrement liés, l'implémentation de HostResolveImportedModule est entièrement synchrone selon la spécification.
Correspond au champ de méthode concrète Link() des enregistrements de module cycliques dans la spécification ECMAScript.
module.namespace
L'objet espace de noms du module. Ceci n'est disponible qu'après la fin de la liaison (module.link()
).
Correspond à l'opération abstraite GetModuleNamespace dans la spécification ECMAScript.
module.status
L'état actuel du module. Sera l'un des suivants :
'unlinked'
:module.link()
n'a pas encore été appelé.'linking'
:module.link()
a été appelé, mais toutes les Promises renvoyées par la fonction de liaison n'ont pas encore été résolues.'linked'
: Le module a été lié avec succès, et toutes ses dépendances sont liées, maismodule.evaluate()
n'a pas encore été appelé.'evaluating'
: Le module est en cours d'évaluation via unmodule.evaluate()
sur lui-même ou un module parent.'evaluated'
: Le module a été évalué avec succès.'errored'
: Le module a été évalué, mais une exception a été levée.
Outre 'errored'
, cette chaîne de caractères d'état correspond au champ [[Status]]
de l'enregistrement de module cyclique de la spécification. 'errored'
correspond à 'evaluated'
dans la spécification, mais avec [[EvaluationError]]
défini sur une valeur différente de undefined
.
Classe : vm.SourceTextModule
Ajouté dans : v9.6.0
[Stable : 1 - Expérimental]
Stable : 1 Stabilité : 1 - Expérimental
Cette fonctionnalité est uniquement disponible avec l'indicateur de commande --experimental-vm-modules
activé.
- Étend : <vm.Module>
La classe vm.SourceTextModule
fournit l'enregistrement de module de texte source tel que défini dans la spécification ECMAScript.
new vm.SourceTextModule(code[, options])
[Historique]
Version | Modifications |
---|---|
v17.0.0, v16.12.0 | Ajout de la prise en charge des attributs d'importation au paramètre importModuleDynamically . |
code
<chaîne de caractères> Code de module JavaScript à analyseroptions
identifier
<chaîne de caractères> Chaîne utilisée dans les traces de pile. Valeur par défaut :'vm:module(i)'
oùi
est un index ascendant spécifique au contexte.cachedData
<Buffer> | <TypedArray> | <DataView> Fournit unBuffer
ou unTypedArray
facultatif, ou unDataView
avec les données du cache de code de V8 pour la source fournie. Lecode
doit être le même que le module à partir duquel cecachedData
a été créé.context
<Objet> L'objet contextualisé tel que renvoyé par la méthodevm.createContext()
, pour compiler et évaluer ceModule
dans. Si aucun contexte n'est spécifié, le module est évalué dans le contexte d'exécution actuel.lineOffset
<entier> Spécifie le décalage du numéro de ligne qui est affiché dans les traces de pile produites par ceModule
. Valeur par défaut :0
.columnOffset
<entier> Spécifie le décalage du numéro de colonne de la première ligne qui est affiché dans les traces de pile produites par ceModule
. Valeur par défaut :0
.initializeImportMeta
<Fonction> Appelé lors de l'évaluation de ceModule
pour initialiser l'import.meta
.meta
<import.meta>module
<vm.SourceTextModule>importModuleDynamically
<Fonction> Utilisé pour spécifier comment les modules doivent être chargés pendant l'évaluation de ce module lorsqueimport()
est appelé. Cette option fait partie de l'API des modules expérimentaux. Nous ne recommandons pas de l'utiliser dans un environnement de production. Pour plus d'informations, voir Prise en charge de l'importation dynamique dans les API de compilation.
Crée une nouvelle instance SourceTextModule
.
Les propriétés affectées à l'objet import.meta
qui sont des objets peuvent permettre au module d'accéder à des informations en dehors du context
spécifié. Utilisez vm.runInContext()
pour créer des objets dans un contexte spécifique.
import vm from 'node:vm'
const contextifiedObject = vm.createContext({ secret: 42 })
const module = new vm.SourceTextModule('Object.getPrototypeOf(import.meta.prop).secret = secret;', {
initializeImportMeta(meta) {
// Remarque : cet objet est créé dans le contexte supérieur. Ainsi,
// Object.getPrototypeOf(import.meta.prop) pointe vers le
// Object.prototype dans le contexte supérieur plutôt que dans
// l'objet contextualisé.
meta.prop = {}
},
})
// Étant donné que le module n'a aucune dépendance, la fonction de liaison ne sera jamais appelée.
await module.link(() => {})
await module.evaluate()
// Maintenant, Object.prototype.secret sera égal à 42.
//
// Pour résoudre ce problème, remplacez
// meta.prop = {};
// ci-dessus par
// meta.prop = vm.runInContext('{}', contextifiedObject);
const vm = require('node:vm')
const contextifiedObject = vm.createContext({ secret: 42 })
;(async () => {
const module = new vm.SourceTextModule('Object.getPrototypeOf(import.meta.prop).secret = secret;', {
initializeImportMeta(meta) {
// Remarque : cet objet est créé dans le contexte supérieur. Ainsi,
// Object.getPrototypeOf(import.meta.prop) pointe vers le
// Object.prototype dans le contexte supérieur plutôt que dans
// l'objet contextualisé.
meta.prop = {}
},
})
// Étant donné que le module n'a aucune dépendance, la fonction de liaison ne sera jamais appelée.
await module.link(() => {})
await module.evaluate()
// Maintenant, Object.prototype.secret sera égal à 42.
//
// Pour résoudre ce problème, remplacez
// meta.prop = {};
// ci-dessus par
// meta.prop = vm.runInContext('{}', contextifiedObject);
})()
sourceTextModule.createCachedData()
Ajouté dans : v13.7.0, v12.17.0
- Retourne : <Buffer>
Crée un cache de code pouvant être utilisé avec l’option cachedData
du constructeur SourceTextModule
. Retourne un Buffer
. Cette méthode peut être appelée plusieurs fois avant que le module n’ait été évalué.
Le cache de code du SourceTextModule
ne contient aucun état observable JavaScript. Le cache de code peut être sauvegardé en toute sécurité avec la source du script et utilisé pour construire plusieurs fois de nouvelles instances SourceTextModule
.
Les fonctions dans la source SourceTextModule
peuvent être marquées comme compilées paresseusement et elles ne sont pas compilées lors de la construction du SourceTextModule
. Ces fonctions seront compilées lors de leur première invocation. Le cache de code sérialise les métadonnées que V8 connaît actuellement sur le SourceTextModule
qu’il peut utiliser pour accélérer les compilations futures.
// Créer un module initial
const module = new vm.SourceTextModule('const a = 1;')
// Créer des données mises en cache à partir de ce module
const cachedData = module.createCachedData()
// Créer un nouveau module en utilisant les données mises en cache. Le code doit être le même.
const module2 = new vm.SourceTextModule('const a = 1;', { cachedData })
Classe : vm.SyntheticModule
Ajouté dans : v13.0.0, v12.16.0
[Stable : 1 - Expérimental]
Stable : 1 Stabilité : 1 - Expérimental
Cette fonctionnalité est uniquement disponible avec l’indicateur de commande --experimental-vm-modules
activé.
- Étend : <vm.Module>
La classe vm.SyntheticModule
fournit l’Enregistrement de module synthétique tel que défini dans la spécification WebIDL. Le but des modules synthétiques est de fournir une interface générique pour exposer des sources non JavaScript aux graphes de modules ECMAScript.
const vm = require('node:vm')
const source = '{ "a": 1 }'
const module = new vm.SyntheticModule(['default'], function () {
const obj = JSON.parse(source)
this.setExport('default', obj)
})
// Utiliser `module` dans la liaison…
new vm.SyntheticModule(exportNames, evaluateCallback[, options])
Ajouté dans : v13.0.0, v12.16.0
exportNames
<string[]> Tableau de noms qui seront exportés depuis le module.evaluateCallback
<Function> Appelée lorsque le module est évalué.options
identifier
<string> Chaîne utilisée dans les traces de pile. Valeur par défaut :'vm:module(i)'
oùi
est un index ascendant spécifique au contexte.context
<Object> L'objet contextualisé tel que renvoyé par la méthodevm.createContext()
, pour compiler et évaluer ceModule
.
Crée une nouvelle instance SyntheticModule
.
Les objets assignés aux exportations de cette instance peuvent permettre aux importateurs du module d'accéder à des informations en dehors du context
spécifié. Utilisez vm.runInContext()
pour créer des objets dans un contexte spécifique.
syntheticModule.setExport(name, value)
Ajouté dans : v13.0.0, v12.16.0
Cette méthode est utilisée après la liaison du module pour définir les valeurs des exportations. Si elle est appelée avant la liaison du module, une erreur ERR_VM_MODULE_STATUS
sera levée.
import vm from 'node:vm'
const m = new vm.SyntheticModule(['x'], () => {
m.setExport('x', 1)
})
await m.link(() => {})
await m.evaluate()
assert.strictEqual(m.namespace.x, 1)
const vm = require('node:vm')
;(async () => {
const m = new vm.SyntheticModule(['x'], () => {
m.setExport('x', 1)
})
await m.link(() => {})
await m.evaluate()
assert.strictEqual(m.namespace.x, 1)
})()
vm.compileFunction(code[, params[, options]])
[Historique]
Version | Modifications |
---|---|
v21.7.0, v20.12.0 | Ajout du support pour vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v19.6.0, v18.15.0 | La valeur de retour inclut désormais cachedDataRejected avec la même sémantique que la version vm.Script si l'option cachedData a été passée. |
v17.0.0, v16.12.0 | Ajout du support pour les attributs d'importation au paramètre importModuleDynamically . |
v15.9.0 | Ajout de l'option importModuleDynamically . |
v14.3.0 | Suppression de importModuleDynamically en raison de problèmes de compatibilité. |
v14.1.0, v13.14.0 | L'option importModuleDynamically est désormais prise en charge. |
v10.10.0 | Ajouté dans la version : v10.10.0 |
code
<string> Le corps de la fonction à compiler.params
<string[]> Un tableau de chaînes contenant tous les paramètres de la fonction.options
<Object>filename
<string> Spécifie le nom de fichier utilisé dans les traces de pile produites par ce script. Défaut :''
.lineOffset
<number> Spécifie le décalage du numéro de ligne qui est affiché dans les traces de pile produites par ce script. Défaut :0
.columnOffset
<number> Spécifie le décalage du numéro de colonne de la première ligne qui est affiché dans les traces de pile produites par ce script. Défaut :0
.cachedData
<Buffer> | <TypedArray> | <DataView> Fournit unBuffer
, unTypedArray
ou unDataView
optionnel avec les données du cache de code de V8 pour la source fournie. Ceci doit être produit par un appel précédent àvm.compileFunction()
avec les mêmescode
etparams
.produceCachedData
<boolean> Spécifie s'il faut produire de nouvelles données de cache. Défaut :false
.parsingContext
<Object> L'objet contextualisé dans lequel la fonction doit être compilée.contextExtensions
<Object[]> Un tableau contenant une collection d'extensions de contexte (objets encapsulant la portée actuelle) à appliquer lors de la compilation. Défaut :[]
.
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Utilisé pour spécifier la manière dont les modules doivent être chargés lors de l'évaluation de cette fonction lorsqueimport()
est appelé. Cette option fait partie de l'API expérimentale des modules. Nous ne recommandons pas de l'utiliser en production. Pour plus d'informations, consultez Support deimport()
dynamique dans les API de compilation.Retourne : <Function>
Compile le code donné dans le contexte fourni (si aucun contexte n'est fourni, le contexte actuel est utilisé), et le retourne encapsulé dans une fonction avec les params
donnés.
vm.constants
Ajouté dans : v21.7.0, v20.12.0
Retourne un objet contenant les constantes couramment utilisées pour les opérations de la VM.
vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER
Ajouté dans : v21.7.0, v20.12.0
[Stable : 1 - Expérimental]
Stable : 1 Stabilité : 1.1 - Développement actif
Une constante qui peut être utilisée comme option importModuleDynamically
pour vm.Script
et vm.compileFunction()
afin que Node.js utilise le chargeur ESM par défaut du contexte principal pour charger le module demandé.
Pour plus d’informations, consultez Prise en charge de import()
dynamique dans les API de compilation.
vm.createContext([contextObject[, options]])
[Historique]
Version | Modifications |
---|---|
v22.8.0, v20.18.0 | L’argument contextObject accepte désormais vm.constants.DONT_CONTEXTIFY . |
v21.7.0, v20.12.0 | Ajout de la prise en charge de vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v21.2.0, v20.11.0 | L’option importModuleDynamically est désormais prise en charge. |
v14.6.0 | L’option microtaskMode est désormais prise en charge. |
v10.0.0 | Le premier argument ne peut plus être une fonction. |
v10.0.0 | L’option codeGeneration est désormais prise en charge. |
v0.3.1 | Ajouté dans : v0.3.1 |
contextObject
<Objet> | <vm.constants.DONT_CONTEXTIFY> | <indéfini> Soitvm.constants.DONT_CONTEXTIFY
soit un objet qui sera contextualisé. Siindéfini
, un objet contextualisé vide sera créé pour assurer la compatibilité descendante.options
<Objet>name
<chaîne de caractères> Nom lisible par l’homme du contexte nouvellement créé. Par défaut :'Contexte VM i'
, oùi
est un index numérique croissant du contexte créé.origin
<chaîne de caractères> Origine correspondant au contexte nouvellement créé à des fins d’affichage. L’origine doit être formatée comme une URL, mais avec uniquement le schéma, l’hôte et le port (si nécessaire), comme la valeur de la propriétéurl.origin
d’un objetURL
. Plus précisément, cette chaîne de caractères doit omettre la barre oblique finale, car elle désigne un chemin. Par défaut :''
.codeGeneration
<Objet>strings
<booléen> Si défini sur faux, tous les appels àeval
ou aux constructeurs de fonctions (Function
,GeneratorFunction
, etc.) lèveront une erreurEvalError
. Par défaut :true
.wasm
<booléen> Si défini sur faux, toute tentative de compilation d’un module WebAssembly lèvera une erreurWebAssembly.CompileError
. Par défaut :true
.microtaskMode
<chaîne de caractères> Si défini surafterEvaluate
, les microtâches (tâches planifiées via lesPromise
et lesasync function
) seront exécutées immédiatement après l’exécution d’un script viascript.runInContext()
. Elles sont incluses dans les portéestimeout
etbreakOnSigint
dans ce cas.importModuleDynamically
<Fonction> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Utilisé pour spécifier comment les modules doivent être chargés lorsqueimport()
est appelé dans ce contexte sans script ou module de référence. Cette option fait partie de l’API expérimentale des modules. Nous ne recommandons pas de l’utiliser en production. Pour plus d’informations, consultez Prise en charge deimport()
dynamique dans les API de compilation.
Retourne : <Objet> objet contextualisé.
Si contextObject
est un objet, la méthode vm.createContext()
préparera cet objet et renverra une référence à celui-ci afin qu’il puisse être utilisé dans les appels à vm.runInContext()
ou script.runInContext()
. À l’intérieur de ces scripts, l’objet global sera encapsulé par contextObject
, conservant toutes ses propriétés existantes mais disposant également des objets et fonctions intégrés que possède tout objet global standard. En dehors des scripts exécutés par le module vm, les variables globales resteront inchangées.
const vm = require('node:vm')
global.globalVar = 3
const context = { globalVar: 1 }
vm.createContext(context)
vm.runInContext('globalVar *= 2;', context)
console.log(context)
// Affiche : { globalVar: 2 }
console.log(global.globalVar)
// Affiche : 3
Si contextObject
est omis (ou passé explicitement comme undefined
), un nouvel objet contextualisé vide sera renvoyé.
Lorsque l’objet global dans le contexte nouvellement créé est contextualisé, il présente quelques particularités par rapport aux objets globaux ordinaires. Par exemple, il ne peut pas être figé. Pour créer un contexte sans les particularités de la contextualisation, passez vm.constants.DONT_CONTEXTIFY
comme argument contextObject
. Consultez la documentation de vm.constants.DONT_CONTEXTIFY
pour plus de détails.
La méthode vm.createContext()
est principalement utile pour créer un contexte unique pouvant être utilisé pour exécuter plusieurs scripts. Par exemple, si vous émulez un navigateur Web, la méthode peut être utilisée pour créer un contexte unique représentant l’objet global d’une fenêtre, puis exécuter toutes les balises \<script\>
ensemble dans ce contexte.
Le name
et l’origin
fournis du contexte sont rendus visibles via l’API de l’inspecteur.
vm.isContext(objet)
Ajouté dans : v0.11.7
Retourne true
si l’objet objet
donné a été contexualisé à l’aide de vm.createContext()
, ou s’il s’agit de l’objet global d’un contexte créé à l’aide de vm.constants.DONT_CONTEXTIFY
.
vm.measureMemory([options])
Ajouté dans : v13.10.0
[Stable : 1 - Expérimental]
Stable : 1 Stabilité : 1 - Expérimental
Mesurer la mémoire connue de V8 et utilisée par tous les contextes connus de l’isolant V8 actuel, ou le contexte principal.
options
<Objet> Facultatif.mode
<chaîne de caractères> Soit'summary'
soit'detailed'
. En mode résumé, seule la mémoire mesurée pour le contexte principal sera retournée. En mode détaillé, la mémoire mesurée pour tous les contextes connus de l’isolant V8 actuel sera retournée. Défaut :'summary'
execution
<chaîne de caractères> Soit'default'
soit'eager'
. Avec l’exécution par défaut, la promesse ne sera pas résolue avant le début de la prochaine collecte de déchets planifiée, ce qui peut prendre un certain temps (ou jamais si le programme se termine avant la prochaine collecte de déchets). Avec l’exécution immédiate, la collecte de déchets sera lancée immédiatement pour mesurer la mémoire. Défaut :'default'
Retourne : <Promise> Si la mémoire est correctement mesurée, la promesse sera résolue avec un objet contenant des informations sur l’utilisation de la mémoire. Sinon, elle sera rejetée avec une erreur
ERR_CONTEXT_NOT_INITIALIZED
.
Le format de l’objet que la Promise retournée peut résoudre est spécifique au moteur V8 et peut changer d’une version de V8 à l’autre.
Le résultat retourné est différent des statistiques retournées par v8.getHeapSpaceStatistics()
en ce sens que vm.measureMemory()
mesure la mémoire accessible par chaque contexte spécifique à V8 dans l’instance actuelle du moteur V8, tandis que le résultat de v8.getHeapSpaceStatistics()
mesure la mémoire occupée par chaque espace de tas dans l’instance V8 actuelle.
const vm = require('node:vm')
// Mesurer la mémoire utilisée par le contexte principal.
vm.measureMemory({ mode: 'summary' })
// Ceci est identique à vm.measureMemory()
.then(result => {
// Le format actuel est :
// {
// total: {
// jsMemoryEstimate: 2418479, jsMemoryRange: [ 2418479, 2745799 ]
// }
// }
console.log(result)
})
const context = vm.createContext({ a: 1 })
vm.measureMemory({ mode: 'detailed', execution: 'eager' }).then(result => {
// Référencez le contexte ici afin qu’il ne soit pas collecté par le ramasse-miettes
// avant que la mesure ne soit terminée.
console.log(context.a)
// {
// total: {
// jsMemoryEstimate: 2574732,
// jsMemoryRange: [ 2574732, 2904372 ]
// },
// current: {
// jsMemoryEstimate: 2438996,
// jsMemoryRange: [ 2438996, 2768636 ]
// },
// other: [
// {
// jsMemoryEstimate: 135736,
// jsMemoryRange: [ 135736, 465376 ]
// }
// ]
// }
console.log(result)
})
vm.runInContext(code, contextifiedObject[, options])
[Historique]
Version | Modifications |
---|---|
v21.7.0, v20.12.0 | Ajout de la prise en charge de vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Ajout de la prise en charge des attributs d'importation au paramètre importModuleDynamically . |
v6.3.0 | L'option breakOnSigint est désormais prise en charge. |
v0.3.1 | Ajouté dans : v0.3.1 |
code
<string> Le code JavaScript à compiler et à exécuter.contextifiedObject
<Object> L'objet contextualisé qui sera utilisé commeglobal
lors de la compilation et de l'exécution ducode
.options
<Object> | <string>filename
<string> Spécifie le nom de fichier utilisé dans les traces de pile produites par ce script. Valeur par défaut :'evalmachine.\<anonymous\>'
.lineOffset
<number> Spécifie le décalage du numéro de ligne affiché dans les traces de pile produites par ce script. Valeur par défaut :0
.columnOffset
<number> Spécifie le décalage du numéro de colonne de la première ligne affiché dans les traces de pile produites par ce script. Valeur par défaut :0
.displayErrors
<boolean> Sitrue
, si une erreurError
se produit lors de la compilation ducode
, la ligne de code à l'origine de l'erreur est attachée à la trace de pile. Valeur par défaut :true
.timeout
<integer> Spécifie le nombre de millisecondes pour exécuter lecode
avant d'arrêter l'exécution. Si l'exécution est interrompue, une erreurError
sera levée. Cette valeur doit être un entier strictement positif.breakOnSigint
<boolean> Sitrue
, la réception deSIGINT
(+) mettra fin à l'exécution et lèvera une erreurError
. Les gestionnaires existants de l'événement qui ont été attachés viaprocess.on('SIGINT')
sont désactivés pendant l'exécution du script, mais continuent de fonctionner après cela. Valeur par défaut :false
.cachedData
<Buffer> | <TypedArray> | <DataView> Fournit unBuffer
ou unTypedArray
, ou unDataView
facultatif avec les données du cache de code de V8 pour la source fournie.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Utilisé pour spécifier comment les modules doivent être chargés pendant l'évaluation de ce script lorsqueimport()
est appelé. Cette option fait partie de l'API expérimentale des modules. Nous ne recommandons pas de l'utiliser dans un environnement de production. Pour plus d'informations, consultez Prise en charge deimport()
dynamique dans les API de compilation.
La méthode vm.runInContext()
compile le code
, l'exécute dans le contexte de contextifiedObject
, puis renvoie le résultat. L'exécution du code n'a pas accès à la portée locale. L'objet contextifiedObject
doit avoir été préalablement contextualisé à l'aide de la méthode vm.createContext()
.
Si options
est une chaîne, elle spécifie le nom de fichier.
L'exemple suivant compile et exécute différents scripts en utilisant un seul objet contextualisé :
const vm = require('node:vm')
const contextObject = { globalVar: 1 }
vm.createContext(contextObject)
for (let i = 0; i < 10; ++i) {
vm.runInContext('globalVar *= 2;', contextObject)
}
console.log(contextObject)
// Affiche : { globalVar: 1024 }
vm.runInNewContext(code[, contextObject[, options]])
[Historique]
Version | Modifications |
---|---|
v22.8.0, v20.18.0 | L'argument contextObject accepte désormais vm.constants.DONT_CONTEXTIFY . |
v21.7.0, v20.12.0 | Ajout de la prise en charge de vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Ajout de la prise en charge des attributs d'importation au paramètre importModuleDynamically . |
v14.6.0 | L'option microtaskMode est désormais prise en charge. |
v10.0.0 | L'option contextCodeGeneration est désormais prise en charge. |
v6.3.0 | L'option breakOnSigint est désormais prise en charge. |
v0.3.1 | Ajouté dans : v0.3.1 |
code
<string> Le code JavaScript à compiler et à exécuter.contextObject
<Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> Soitvm.constants.DONT_CONTEXTIFY
soit un objet qui sera contexualisé. Siundefined
, un objet contextualisé vide sera créé pour assurer la compatibilité descendante.filename
<string> Spécifie le nom de fichier utilisé dans les traces de pile produites par ce script. Défaut :'evalmachine.\<anonymous\>'
.lineOffset
<number> Spécifie le décalage du numéro de ligne qui est affiché dans les traces de pile produites par ce script. Défaut :0
.columnOffset
<number> Spécifie le décalage du numéro de colonne de la première ligne qui est affiché dans les traces de pile produites par ce script. Défaut :0
.displayErrors
<boolean> Lorsqu'il est défini surtrue
, si une erreurError
se produit lors de la compilation ducode
, la ligne de code à l'origine de l'erreur est ajoutée à la trace de pile. Défaut :true
.timeout
<integer> Spécifie le nombre de millisecondes pour exécutercode
avant d'arrêter l'exécution. Si l'exécution est interrompue, une erreurError
sera levée. Cette valeur doit être un entier strictement positif.breakOnSigint
<boolean> Sitrue
, la réception deSIGINT
(+) interrompra l'exécution et lèvera une erreurError
. Les gestionnaires existants de l'événement qui ont été attachés viaprocess.on('SIGINT')
sont désactivés pendant l'exécution du script, mais continuent de fonctionner après cela. Défaut :false
.contextName
<string> Nom lisible par l'homme du contexte nouvellement créé. Défaut :'VM Context i'
, oùi
est un index numérique ascendant du contexte créé.contextOrigin
<string> Origine correspondant au contexte nouvellement créé à des fins d'affichage. L'origine doit être formatée comme une URL, mais avec uniquement le schéma, l'hôte et le port (si nécessaire), comme la valeur de la propriétéurl.origin
d'un objetURL
. Plus précisément, cette chaîne doit omettre la barre oblique de fin, car elle désigne un chemin. Défaut :''
.contextCodeGeneration
<Object>strings
<boolean> Si défini sur false, tout appel àeval
ou aux constructeurs de fonctions (Function
,GeneratorFunction
, etc.) lèvera une erreurEvalError
. Défaut :true
.wasm
<boolean> Si défini sur false, toute tentative de compilation d'un module WebAssembly lèvera une erreurWebAssembly.CompileError
. Défaut :true
.cachedData
<Buffer> | <TypedArray> | <DataView> Fournit unBuffer
ou unTypedArray
, ou unDataView
optionnel avec les données du cache de code de V8 pour la source fournie.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Utilisé pour spécifier comment les modules doivent être chargés pendant l'évaluation de ce script lorsqueimport()
est appelé. Cette option fait partie de l'API expérimentale des modules. Nous ne recommandons pas de l'utiliser dans un environnement de production. Pour plus d'informations, consultez Prise en charge deimport()
dynamique dans les API de compilation.microtaskMode
<string> Si défini surafterEvaluate
, les microtâches (tâches planifiées via lesPromise
et lesasync function
) seront exécutées immédiatement après l'exécution du script. Elles sont incluses dans les portéestimeout
etbreakOnSigint
dans ce cas.
Retourne : <any> le résultat de la toute dernière instruction exécutée dans le script.
Cette méthode est un raccourci pour (new vm.Script(code, options)).runInContext(vm.createContext(options), options)
. Si options
est une chaîne, elle spécifie le nom du fichier.
Elle fait plusieurs choses à la fois :
L'exemple suivant compile et exécute un code qui incrémente une variable globale et en définit une nouvelle. Ces variables globales sont contenues dans contextObject
.
const vm = require('node:vm')
const contextObject = {
animal: 'cat',
count: 2,
}
vm.runInNewContext('count += 1; name = "kitty"', contextObject)
console.log(contextObject)
// Affiche : { animal: 'cat', count: 3, name: 'kitty' }
// Cela lèverait une erreur si le contexte est créé à partir d'un objet contextualisé.
// vm.constants.DONT_CONTEXTIFY permet de créer des contextes avec des objets globaux ordinaires qui
// peuvent être figés.
const frozenContext = vm.runInNewContext('Object.freeze(globalThis); globalThis;', vm.constants.DONT_CONTEXTIFY)
vm.runInThisContext(code[, options])
[Historique]
Version | Modifications |
---|---|
v21.7.0, v20.12.0 | Ajout de la prise en charge de vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Ajout de la prise en charge des attributs d'importation au paramètre importModuleDynamically . |
v6.3.0 | L'option breakOnSigint est désormais prise en charge. |
v0.3.1 | Ajouté dans : v0.3.1 |
code
<string> Le code JavaScript à compiler et à exécuter.filename
<string> Spécifie le nom de fichier utilisé dans les traces de pile produites par ce script. Valeur par défaut :'evalmachine.\<anonymous\>'
.lineOffset
<number> Spécifie le décalage du numéro de ligne qui est affiché dans les traces de pile produites par ce script. Valeur par défaut :0
.columnOffset
<number> Spécifie le décalage du numéro de colonne de la première ligne qui est affiché dans les traces de pile produites par ce script. Valeur par défaut :0
.displayErrors
<boolean> Lorsque la valeur esttrue
, si une erreurError
se produit lors de la compilation ducode
, la ligne de code à l'origine de l'erreur est jointe à la trace de pile. Valeur par défaut :true
.timeout
<integer> Spécifie le nombre de millisecondes pour exécutercode
avant d'arrêter l'exécution. Si l'exécution est interrompue, une erreurError
est levée. Cette valeur doit être un entier strictement positif.breakOnSigint
<boolean> Si la valeur esttrue
, la réception deSIGINT
(+) met fin à l'exécution et lève une erreurError
. Les gestionnaires existants de l'événement qui ont été attachés viaprocess.on('SIGINT')
sont désactivés pendant l'exécution du script, mais continuent de fonctionner après cela. Valeur par défaut :false
.cachedData
<Buffer> | <TypedArray> | <DataView> Fournit unBuffer
, unTypedArray
ou unDataView
facultatif avec les données du cache de code de V8 pour la source fournie.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Utilisé pour spécifier comment les modules doivent être chargés pendant l'évaluation de ce script lorsqueimport()
est appelé. Cette option fait partie de l'API expérimentale des modules. Nous ne recommandons pas de l'utiliser dans un environnement de production. Pour plus d'informations, consultez Prise en charge deimport()
dynamique dans les API de compilation.
Retourne : <any> le résultat de la toute dernière instruction exécutée dans le script.
vm.runInThisContext()
compile code
, l'exécute dans le contexte du global
actuel et renvoie le résultat. L'exécution du code n'a pas accès à la portée locale, mais a accès à l'objet global
actuel.
Si options
est une chaîne, alors elle spécifie le nom de fichier.
L'exemple suivant illustre l'utilisation de vm.runInThisContext()
et de la fonction JavaScript eval()
pour exécuter le même code :
const vm = require('node:vm')
let localVar = 'initial value'
const vmResult = vm.runInThisContext('localVar = "vm";')
console.log(`vmResult: '${vmResult}', localVar: '${localVar}'`)
// Affiche : vmResult: 'vm', localVar: 'initial value'
const evalResult = eval('localVar = "eval";')
console.log(`evalResult: '${evalResult}', localVar: '${localVar}'`)
// Affiche : evalResult: 'eval', localVar: 'eval'
Comme vm.runInThisContext()
n'a pas accès à la portée locale, localVar
est inchangé. En revanche, eval()
a accès à la portée locale, donc la valeur localVar
est modifiée. De cette façon, vm.runInThisContext()
ressemble beaucoup à un appel eval()
indirect, par exemple (0,eval)('code')
.
Exemple : Exécution d'un serveur HTTP dans une VM
Lors de l'utilisation de script.runInThisContext()
ou de vm.runInThisContext()
, le code est exécuté dans le contexte global V8 courant. Le code passé à ce contexte VM aura sa propre portée isolée.
Pour exécuter un serveur web simple à l'aide du module node:http
, le code passé au contexte doit soit appeler require('node:http')
lui-même, soit avoir une référence au module node:http
qui lui est passée. Par exemple :
'use strict'
const vm = require('node:vm')
const code = `
((require) => {
const http = require('node:http');
http.createServer((request, response) => {
response.writeHead(200, { 'Content-Type': 'text/plain' });
response.end('Hello World\\n');
}).listen(8124);
console.log('Serveur en cours d\'exécution sur http://127.0.0.1:8124/');
})`
vm.runInThisContext(code)(require)
Le require()
dans le cas ci-dessus partage l'état avec le contexte duquel il est passé. Cela peut introduire des risques lorsque du code non fiable est exécuté, par exemple en modifiant les objets du contexte de manière indésirable.
Que signifie « contextifier » un objet ?
Tout JavaScript exécuté dans Node.js s'exécute dans la portée d'un « contexte ». Selon le Guide de l'intégrateur V8 :
Lorsque la méthode vm.createContext()
est appelée avec un objet, l'argument contextObject
sera utilisé pour encapsuler l'objet global d'une nouvelle instance d'un contexte V8 (si contextObject
est undefined
, un nouvel objet sera créé à partir du contexte courant avant sa contextualisation). Ce contexte V8 fournit au code
exécuté à l'aide des méthodes du module node:vm
un environnement global isolé dans lequel il peut fonctionner. Le processus de création du contexte V8 et de son association avec le contextObject
dans le contexte externe est ce que ce document appelle « contextifier » l'objet.
La contextualisation introduirait quelques bizarreries à la valeur globalThis
dans le contexte. Par exemple, elle ne peut pas être figée, et elle n'est pas référentiellement égale à contextObject
dans le contexte externe.
const vm = require('node:vm')
// Une option `contextObject` indéfinie contextualise l'objet global.
const context = vm.createContext()
console.log(vm.runInContext('globalThis', context) === context) // false
// Un objet global contextualisé ne peut pas être figé.
try {
vm.runInContext('Object.freeze(globalThis);', context)
} catch (e) {
console.log(e) // TypeError: Impossible de figer
}
console.log(vm.runInContext('globalThis.foo = 1; foo;', context)) // 1
Pour créer un contexte avec un objet global ordinaire et accéder à un proxy global dans le contexte externe avec moins de bizarreries, spécifiez vm.constants.DONT_CONTEXTIFY
comme argument contextObject
.
vm.constants.DONT_CONTEXTIFY
Cette constante, lorsqu'elle est utilisée comme argument contextObject
dans les API vm, indique à Node.js de créer un contexte sans encapsuler son objet global avec un autre objet de manière spécifique à Node.js. En conséquence, la valeur globalThis
à l'intérieur du nouveau contexte se comporterait plus près d'une valeur ordinaire.
const vm = require('node:vm')
// Utilisez vm.constants.DONT_CONTEXTIFY pour figer l'objet global.
const context = vm.createContext(vm.constants.DONT_CONTEXTIFY)
vm.runInContext('Object.freeze(globalThis);', context)
try {
vm.runInContext('bar = 1; bar;', context)
} catch (e) {
console.log(e) // Uncaught ReferenceError: bar is not defined
}
Lorsque vm.constants.DONT_CONTEXTIFY
est utilisé comme argument contextObject
pour vm.createContext()
, l'objet retourné est un objet de type proxy pour l'objet global dans le nouveau contexte avec moins de particularités spécifiques à Node.js. Il est référentiellement égal à la valeur globalThis
dans le nouveau contexte, peut être modifié de l'extérieur du contexte et peut être utilisé pour accéder directement aux éléments intégrés dans le nouveau contexte.
const vm = require('node:vm')
const context = vm.createContext(vm.constants.DONT_CONTEXTIFY)
// L'objet retourné est référentiellement égal à globalThis dans le nouveau contexte.
console.log(vm.runInContext('globalThis', context) === context) // true
// Peut être utilisé pour accéder aux globales dans le nouveau contexte directement.
console.log(context.Array) // [Function: Array]
vm.runInContext('foo = 1;', context)
console.log(context.foo) // 1
context.bar = 1
console.log(vm.runInContext('bar;', context)) // 1
// Peut être figé et cela affecte le contexte interne.
Object.freeze(context)
try {
vm.runInContext('baz = 1; baz;', context)
} catch (e) {
console.log(e) // Uncaught ReferenceError: baz is not defined
}
Interactions de délai d'attente avec les tâches asynchrones et les Promises
Les Promise
et les async function
peuvent planifier des tâches exécutées par le moteur JavaScript de manière asynchrone. Par défaut, ces tâches sont exécutées une fois que toutes les fonctions JavaScript de la pile actuelle ont fini de s'exécuter. Cela permet d'échapper à la fonctionnalité des options timeout
et breakOnSigint
.
Par exemple, le code suivant exécuté par vm.runInNewContext()
avec un délai d'attente de 5 millisecondes planifie une boucle infinie à exécuter après la résolution d'une promesse. La boucle planifiée n'est jamais interrompue par le délai d'attente :
const vm = require('node:vm')
function loop() {
console.log('entering loop')
while (1) console.log(Date.now())
}
vm.runInNewContext('Promise.resolve().then(() => loop());', { loop, console }, { timeout: 5 })
// Ceci est imprimé *avant* 'entering loop' (!)
console.log('done executing')
Ceci peut être résolu en passant microtaskMode: 'afterEvaluate'
au code qui crée le Context
:
const vm = require('node:vm')
function loop() {
while (1) console.log(Date.now())
}
vm.runInNewContext(
'Promise.resolve().then(() => loop());',
{ loop, console },
{ timeout: 5, microtaskMode: 'afterEvaluate' }
)
Dans ce cas, la microtâche planifiée via promise.then()
sera exécutée avant le retour de vm.runInNewContext()
, et sera interrompue par la fonctionnalité timeout
. Ceci s'applique uniquement au code exécuté dans un vm.Context
, donc par exemple vm.runInThisContext()
ne prend pas cette option.
Les rappels Promise sont entrés dans la file d'attente des microtâches du contexte dans lequel ils ont été créés. Par exemple, si () =\> loop()
est remplacé par simplement loop
dans l'exemple ci-dessus, alors loop
sera poussé dans la file d'attente globale des microtâches, car il s'agit d'une fonction du contexte externe (principal), et pourra donc également échapper au délai d'attente.
Si les fonctions de planification asynchrone telles que process.nextTick()
, queueMicrotask()
, setTimeout()
, setImmediate()
, etc. sont rendues disponibles dans un vm.Context
, les fonctions qui leur sont passées seront ajoutées aux files d'attente globales, qui sont partagées par tous les contextes. Par conséquent, les rappels passés à ces fonctions ne sont pas contrôlables non plus par le délai d'attente.
Prise en charge de import()
dynamique dans les API de compilation
Les API suivantes prennent en charge une option importModuleDynamically
pour activer import()
dynamique dans le code compilé par le module vm
.
new vm.Script
vm.compileFunction()
new vm.SourceTextModule
vm.runInThisContext()
vm.runInContext()
vm.runInNewContext()
vm.createContext()
Cette option fait toujours partie de l'API expérimentale des modules. Nous ne recommandons pas de l'utiliser en environnement de production.
Lorsque l'option importModuleDynamically
n'est pas spécifiée ou est indéfinie
Si cette option n'est pas spécifiée, ou si elle est undefined
, le code contenant import()
peut toujours être compilé par les API vm
, mais lorsque le code compilé est exécuté et qu'il appelle effectivement import()
, le résultat sera rejeté avec ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING
.
Lorsque importModuleDynamically
est vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER
Cette option n'est actuellement pas prise en charge pour vm.SourceTextModule
.
Avec cette option, lorsqu'un import()
est initié dans le code compilé, Node.js utilisera le chargeur ESM par défaut du contexte principal pour charger le module demandé et le renvoyer au code en cours d'exécution.
Cela donne accès aux modules intégrés de Node.js tels que fs
ou http
au code en cours de compilation. Si le code est exécuté dans un contexte différent, sachez que les objets créés par les modules chargés à partir du contexte principal proviennent toujours du contexte principal et ne sont pas instanceof
les classes intégrées du nouveau contexte.
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 : l’URL chargée à partir du contexte principal n’est pas une instance de la classe Function
// dans le nouveau contexte.
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 : l’URL chargée à partir du contexte principal n’est pas une instance de la classe Function
// dans le nouveau contexte.
script.runInNewContext().then(console.log)
Cette option permet également au script ou à la fonction de charger des modules utilisateur :
import { Script, constants } from 'node:vm'
import { resolve } from 'node:path'
import { writeFileSync } from 'node:fs'
// Écrire test.js et test.txt dans le répertoire où le script actuel
// en cours d’exécution est situé.
writeFileSync(resolve(import.meta.dirname, 'test.mjs'), 'export const filename = "./test.json";')
writeFileSync(resolve(import.meta.dirname, 'test.json'), '{"hello": "world"}')
// Compiler un script qui charge test.mjs puis test.json
// comme si le script était placé dans le même répertoire.
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')
// Écrire test.js et test.txt dans le répertoire où le script actuel
// en cours d’exécution est situé.
writeFileSync(resolve(__dirname, 'test.mjs'), 'export const filename = "./test.json";')
writeFileSync(resolve(__dirname, 'test.json'), '{"hello": "world"}')
// Compiler un script qui charge test.mjs puis test.json
// comme si le script était placé dans le même répertoire.
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)
Il existe quelques mises en garde concernant le chargement des modules utilisateur à l'aide du chargeur par défaut du contexte principal :
Lorsque importModuleDynamically
est une fonction
Lorsque importModuleDynamically
est une fonction, elle sera invoquée lorsque import()
est appelé dans le code compilé afin de permettre aux utilisateurs de personnaliser la façon dont le module demandé doit être compilé et évalué. Actuellement, l'instance Node.js doit être lancée avec l'indicateur --experimental-vm-modules
pour que cette option fonctionne. Si l'indicateur n'est pas défini, ce rappel sera ignoré. Si le code évalué appelle effectivement import()
, le résultat sera rejeté avec ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG
.
Le rappel importModuleDynamically(specifier, referrer, importAttributes)
a la signature suivante :
specifier
<string> spécificateur passé àimport()
referrer
<vm.Script> | <Function> | <vm.SourceTextModule> | <Object> Le référent est levm.Script
compilé pournew vm.Script
,vm.runInThisContext
,vm.runInContext
etvm.runInNewContext
. C'est laFunction
compilée pourvm.compileFunction
, levm.SourceTextModule
compilé pournew vm.SourceTextModule
, et le contexteObject
pourvm.createContext()
.importAttributes
<Object> La valeur"with"
passée au paramètre optionneloptionsExpression
, ou un objet vide si aucune valeur n'a été fournie.- Retourne : <Module Namespace Object> | <vm.Module> Il est recommandé de retourner un
vm.Module
afin de profiter du suivi des erreurs et d'éviter les problèmes avec les espaces de noms qui contiennent des exportations de fonctionsthen
.
// Ce script doit être exécuté avec --experimental-vm-modules.
import { Script, SyntheticModule } from 'node:vm'
const script = new Script('import("foo.json", { with: { type: "json" } })', {
async importModuleDynamically(specifier, referrer, importAttributes) {
console.log(specifier) // 'foo.json'
console.log(referrer) // Le script compilé
console.log(importAttributes) // { type: 'json' }
const m = new SyntheticModule(['bar'], () => {})
await m.link(() => {})
m.setExport('bar', { hello: 'world' })
return m
},
})
const result = await script.runInThisContext()
console.log(result) // { bar: { hello: 'world' } }
// Ce script doit être exécuté avec --experimental-vm-modules.
const { Script, SyntheticModule } = require('node:vm')
;(async function main() {
const script = new Script('import("foo.json", { with: { type: "json" } })', {
async importModuleDynamically(specifier, referrer, importAttributes) {
console.log(specifier) // 'foo.json'
console.log(referrer) // Le script compilé
console.log(importAttributes) // { type: 'json' }
const m = new SyntheticModule(['bar'], () => {})
await m.link(() => {})
m.setExport('bar', { hello: 'world' })
return m
},
})
const result = await script.runInThisContext()
console.log(result) // { bar: { hello: 'world' } }
})()