VM (executando JavaScript)
[Estável: 2 - Estável]
Estável: 2 Estabilidade: 2 - Estável
Código-fonte: lib/vm.js
O módulo node:vm
permite compilar e executar código dentro de contextos da Máquina Virtual V8.
O módulo node:vm
não é um mecanismo de segurança. Não o utilize para executar código não confiável.
O código JavaScript pode ser compilado e executado imediatamente ou compilado, salvo e executado posteriormente.
Um caso de uso comum é executar o código em um contexto V8 diferente. Isso significa que o código invocado tem um objeto global diferente do código que o invoca.
Pode-se fornecer o contexto contextizando um objeto. O código invocado trata qualquer propriedade no contexto como uma variável global. Quaisquer alterações em variáveis globais causadas pelo código invocado são refletidas no objeto de contexto.
const vm = require('node:vm')
const x = 1
const context = { x: 2 }
vm.createContext(context) // Contextiza o objeto.
const code = 'x += 40; var y = 17;'
// `x` e `y` são variáveis globais no contexto.
// Inicialmente, x tem o valor 2 porque esse é o valor de context.x.
vm.runInContext(code, context)
console.log(context.x) // 42
console.log(context.y) // 17
console.log(x) // 1; y não está definido.
Classe: vm.Script
Adicionado em: v0.3.1
Instâncias da classe vm.Script
contêm scripts pré-compilados que podem ser executados em contextos específicos.
new vm.Script(code[, options])
[Histórico]
Versão | Alterações |
---|---|
v21.7.0, v20.12.0 | Adicionou suporte para vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Adicionou suporte para atributos de importação ao parâmetro importModuleDynamically . |
v10.6.0 | O produceCachedData está depreciado em favor de script.createCachedData() . |
v5.7.0 | As opções cachedData e produceCachedData agora são suportadas. |
v0.3.1 | Adicionada em: v0.3.1 |
code
<string> O código JavaScript a ser compilado.options
<Object> | <string>filename
<string> Especifica o nome do arquivo usado nos rastros de pilha produzidos por este script. Padrão:'evalmachine.\<anonymous\>'
.lineOffset
<number> Especifica o offset do número da linha que é exibido nos rastros de pilha produzidos por este script. Padrão:0
.columnOffset
<number> Especifica o offset do número da coluna da primeira linha que é exibido nos rastros de pilha produzidos por este script. Padrão:0
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornece umBuffer
ouTypedArray
opcional, ouDataView
com os dados do cache de código do V8 para a fonte fornecida. Quando fornecido, o valorcachedDataRejected
será definido comotrue
oufalse
, dependendo da aceitação dos dados pelo V8.produceCachedData
<boolean> Quandotrue
e nenhumcachedData
estiver presente, o V8 tentará produzir dados do cache de código paracode
. Após o sucesso, umBuffer
com os dados do cache de código do V8 será produzido e armazenado na propriedadecachedData
da instânciavm.Script
retornada. O valorcachedDataProduced
será definido comotrue
oufalse
, dependendo se os dados do cache de código são produzidos com sucesso. Esta opção está depreciada em favor descript.createCachedData()
. Padrão:false
.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Usado para especificar como os módulos devem ser carregados durante a avaliação deste script quandoimport()
é chamado. Esta opção faz parte da API experimental de módulos. Não recomendamos usá-la em um ambiente de produção. Para informações detalhadas, consulte Suporte deimport()
dinâmico em APIs de compilação.
Se options
for uma string, então ela especifica o nome do arquivo.
Criar um novo objeto vm.Script
compila code
, mas não o executa. O vm.Script
compilado pode ser executado posteriormente várias vezes. O code
não está vinculado a nenhum objeto global; em vez disso, ele é vinculado antes de cada execução, apenas para aquela execução.
script.cachedDataRejected
Adicionado em: v5.7.0
Quando cachedData
é fornecido para criar o vm.Script
, este valor será definido como true
ou false
dependendo da aceitação dos dados pelo V8. Caso contrário, o valor é undefined
.
script.createCachedData()
Adicionado em: v10.6.0
- Retorna: <Buffer>
Cria um cache de código que pode ser usado com a opção cachedData
do construtor Script
. Retorna um Buffer
. Este método pode ser chamado a qualquer momento e qualquer número de vezes.
O cache de código do Script
não contém nenhum estado observável JavaScript. O cache de código pode ser salvo juntamente com a fonte do script e usado para construir novas instâncias de Script
várias vezes.
As funções na fonte do Script
podem ser marcadas como compiladas preguiçosamente e não são compiladas na construção do Script
. Essas funções serão compiladas quando forem invocadas pela primeira vez. O cache de código serializa os metadados que o V8 conhece atualmente sobre o Script
que ele pode usar para acelerar compilações futuras.
const script = new vm.Script(`
function add(a, b) {
return a + b;
}
const x = add(1, 2);
`)
const cacheWithoutAdd = script.createCachedData()
// Em `cacheWithoutAdd` a função `add()` está marcada para compilação completa
// após a invocação.
script.runInThisContext()
const cacheWithAdd = script.createCachedData()
// `cacheWithAdd` contém a função `add()` totalmente compilada.
script.runInContext(contextifiedObject[, options])
[Histórico]
Versão | Alterações |
---|---|
v6.3.0 | A opção breakOnSigint é agora suportada. |
v0.3.1 | Adicionada em: v0.3.1 |
contextifiedObject
<Object> Um objeto contextificado como retornado pelo métodovm.createContext()
.options
<Object>displayErrors
<boolean> Quandotrue
, se umError
ocorrer durante a compilação docode
, a linha de código que causou o erro é anexada ao rastreamento de pilha. Padrão:true
.timeout
<integer> Especifica o número de milissegundos para executarcode
antes de terminar a execução. Se a execução for terminada, umError
será lançado. Este valor deve ser um inteiro estritamente positivo.breakOnSigint
<boolean> Setrue
, receberSIGINT
(+) terminará a execução e lançará umError
. Os manipuladores existentes para o evento que foram anexados viaprocess.on('SIGINT')
são desabilitados durante a execução do script, mas continuam a funcionar depois disso. Padrão:false
.
Retorna: <any> o resultado da última instrução executada no script.
Executa o código compilado contido pelo objeto vm.Script
dentro do contextifiedObject
fornecido e retorna o resultado. A execução do código não tem acesso ao escopo local.
O exemplo a seguir compila código que incrementa uma variável global, define o valor de outra variável global e, em seguida, executa o código várias vezes. As variáveis globais estão contidas no objeto 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)
// Imprime: { animal: 'cat', count: 12, name: 'kitty' }
Usar as opções timeout
ou breakOnSigint
resultará em novos loops de eventos e threads correspondentes sendo iniciados, que têm uma sobrecarga de desempenho diferente de zero.
script.runInNewContext([contextObject[, options]])
[Histórico]
Versão | Alterações |
---|---|
v22.8.0, v20.18.0 | O argumento contextObject agora aceita vm.constants.DONT_CONTEXTIFY . |
v14.6.0 | A opção microtaskMode agora é suportada. |
v10.0.0 | A opção contextCodeGeneration agora é suportada. |
v6.3.0 | A opção breakOnSigint agora é suportada. |
v0.3.1 | Adicionado em: v0.3.1 |
contextObject
<Objeto> | <vm.constants.DONT_CONTEXTIFY> | <indefinido> Ouvm.constants.DONT_CONTEXTIFY
ou um objeto que será contextificado. Seindefinido
, um objeto contextificado vazio será criado para compatibilidade com versões anteriores.options
<Objeto>displayErrors
<booleano> Quandotrue
, se umError
ocorrer durante a compilação docode
, a linha de código que causou o erro é anexada ao rastro da pilha. Padrão:true
.timeout
<inteiro> Especifica o número de milissegundos para executarcode
antes de terminar a execução. Se a execução for terminada, umError
será lançado. Este valor deve ser um inteiro estritamente positivo.breakOnSigint
<booleano> Setrue
, receberSIGINT
(+) terminará a execução e lançará umError
. Os manipuladores existentes para o evento que foram anexados viaprocess.on('SIGINT')
são desabilitados durante a execução do script, mas continuam a funcionar depois disso. Padrão:false
.contextName
<string> Nome legível por humanos do contexto recém-criado. Padrão:'VM Context i'
, ondei
é um índice numérico ascendente do contexto criado.contextOrigin
<string> Origem correspondente ao contexto recém-criado para fins de exibição. A origem deve ser formatada como uma URL, mas apenas com o esquema, host e porta (se necessário), como o valor da propriedadeurl.origin
de um objetoURL
. Mais notavelmente, esta string deve omitir a barra final, pois isso denota um caminho. Padrão:''
.contextCodeGeneration
<Objeto>strings
<booleano> Se definido como false, qualquer chamada paraeval
ou construtores de função (Function
,GeneratorFunction
, etc.) lançará umEvalError
. Padrão:true
.wasm
<booleano> Se definido como false, qualquer tentativa de compilar um módulo WebAssembly lançará umWebAssembly.CompileError
. Padrão:true
.microtaskMode
<string> Se definido comoafterEvaluate
, microtarefas (tarefas agendadas através dePromise
s easync function
s) serão executadas imediatamente após a execução do script. Elas são incluídas nos escopostimeout
ebreakOnSigint
nesse caso.
Retorna: <qualquer> o resultado da última instrução executada no script.
Este método é um atalho para script.runInContext(vm.createContext(options), options)
. Ele faz várias coisas ao mesmo tempo:
O exemplo a seguir compila código que define uma variável global, depois executa o código várias vezes em contextos diferentes. As variáveis globais são definidas e contidas em cada context
individual.
const vm = require('node:vm')
const script = new vm.Script('globalVar = "set"')
const contexts = [{}, {}, {}]
contexts.forEach(context => {
script.runInNewContext(context)
})
console.log(contexts)
// Imprime: [{ globalVar: 'set' }, { globalVar: 'set' }, { globalVar: 'set' }]
// Isto lançaria uma exceção se o contexto fosse criado a partir de um objeto contextificado.
// vm.constants.DONT_CONTEXTIFY permite criar contextos com objetos globais comuns
// que podem ser congelados.
const freezeScript = new vm.Script('Object.freeze(globalThis); globalThis;')
const frozenContext = freezeScript.runInNewContext(vm.constants.DONT_CONTEXTIFY)
script.runInThisContext([options])
[Histórico]
Versão | Alterações |
---|---|
v6.3.0 | A opção breakOnSigint agora é suportada. |
v0.3.1 | Adicionada em: v0.3.1 |
options
<Objeto>displayErrors
<booleano> Quandotrue
, se umError
ocorrer durante a compilação docode
, a linha de código que causou o erro é anexada ao rastreamento da pilha. Padrão:true
.timeout
<inteiro> Especifica o número de milissegundos para executarcode
antes de terminar a execução. Se a execução for terminada, umError
será lançado. Este valor deve ser um inteiro estritamente positivo.breakOnSigint
<booleano> Setrue
, receberSIGINT
(+) terminará a execução e lançará umError
. Os manipuladores existentes para o evento que foram anexados viaprocess.on('SIGINT')
são desabilitados durante a execução do script, mas continuam a funcionar após isso. Padrão:false
.
Retorna: <qualquer> o resultado da última instrução executada no script.
Executa o código compilado contido pelo vm.Script
dentro do contexto do objeto global
atual. A execução do código não tem acesso ao escopo local, mas tem acesso ao objeto global
atual.
O exemplo a seguir compila o código que incrementa uma variável global
e, em seguida, executa esse código várias vezes:
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
Adicionado em: v19.1.0, v18.13.0
Quando o script é compilado de uma fonte que contém um comentário mágico de mapeamento de origem, esta propriedade será definida como a URL do mapeamento de origem.
import vm from 'node:vm'
const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`)
console.log(script.sourceMapURL)
// Imprime: sourcemap.json
const vm = require('node:vm')
const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`)
console.log(script.sourceMapURL)
// Imprime: sourcemap.json
Classe: vm.Module
Adicionado em: v13.0.0, v12.16.0
[Estável: 1 - Experimental]
Estável: 1 Estabilidade: 1 - Experimental
Este recurso está disponível apenas com a sinalização de comando --experimental-vm-modules
ativada.
A classe vm.Module
fornece uma interface de baixo nível para usar módulos ECMAScript em contextos de VM. É a contraparte da classe vm.Script
que espelha de perto os Registros de Módulo conforme definidos na especificação ECMAScript.
Ao contrário de vm.Script
, no entanto, cada objeto vm.Module
está vinculado a um contexto desde sua criação. As operações em objetos vm.Module
são intrinsecamente assíncronas, em contraste com a natureza síncrona dos objetos vm.Script
. O uso de funções 'async' pode ajudar a manipular objetos vm.Module
.
Usar um objeto vm.Module
requer três etapas distintas: criação/análise, ligação e avaliação. Essas três etapas são ilustradas no exemplo a seguir.
Esta implementação está em um nível inferior ao Carregador de Módulo ECMAScript. Também não há como interagir com o Carregador ainda, embora o suporte esteja planejado.
import vm from 'node:vm'
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
})
// Etapa 1
//
// Crie um Módulo construindo um novo objeto `vm.SourceTextModule`. Isso
// analisa o texto de origem fornecido, lançando um `SyntaxError` se algo der
// errado. Por padrão, um Módulo é criado no contexto superior. Mas aqui,
// especificamos `contextifiedObject` como o contexto ao qual este Módulo pertence.
//
// Aqui, tentamos obter a exportação padrão do módulo "foo" e
// colocá-la no vínculo local "secret".
const bar = new vm.SourceTextModule(
`
import s from 'foo';
s;
print(s);
`,
{ context: contextifiedObject }
)
// Etapa 2
//
// "Vincule" as dependências importadas deste Módulo a ele.
//
// O callback de vinculação fornecido (o "vinculador") aceita dois argumentos: o
// módulo pai (`bar` neste caso) e a string que é o especificador do
// módulo importado. O callback deve retornar um Módulo que
// corresponde ao especificador fornecido, com certos requisitos documentados
// em `module.link()`.
//
// Se a vinculação não tiver começado para o Módulo retornado, o mesmo callback
// de vinculação será chamado no Módulo retornado.
//
// Mesmo os Módulos de nível superior sem dependências devem ser explicitamente
// vinculados. O callback fornecido, no entanto, nunca seria chamado.
//
// O método link() retorna uma Promise que será resolvida quando todas as
// Promises retornadas pelo vinculador forem resolvidas.
//
// Nota: Este é um exemplo artificial, pois a função vinculador cria um novo
// módulo "foo" a cada vez que é chamada. Em um sistema de módulo completo, um
// cache provavelmente seria usado para evitar módulos duplicados.
async function linker(specifier, referencingModule) {
if (specifier === 'foo') {
return new vm.SourceTextModule(
`
// A variável "secret" se refere à variável global que adicionamos a
// "contextifiedObject" ao criar o contexto.
export default secret;
`,
{ context: referencingModule.context }
)
// Usar `contextifiedObject` em vez de `referencingModule.context`
// aqui também funcionaria.
}
throw new Error(`Não foi possível resolver a dependência: ${specifier}`)
}
await bar.link(linker)
// Etapa 3
//
// Avalie o Módulo. O método evaluate() retorna uma promise que será
// resolvida após o módulo terminar de ser avaliado.
// Imprime 42.
await bar.evaluate()
const vm = require('node:vm')
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
})
;(async () => {
// Etapa 1
//
// Crie um Módulo construindo um novo objeto `vm.SourceTextModule`. Isso
// analisa o texto de origem fornecido, lançando um `SyntaxError` se algo der
// errado. Por padrão, um Módulo é criado no contexto superior. Mas aqui,
// especificamos `contextifiedObject` como o contexto ao qual este Módulo pertence.
//
// Aqui, tentamos obter a exportação padrão do módulo "foo" e
// colocá-la no vínculo local "secret".
const bar = new vm.SourceTextModule(
`
import s from 'foo';
s;
print(s);
`,
{ context: contextifiedObject }
)
// Etapa 2
//
// "Vincule" as dependências importadas deste Módulo a ele.
//
// O callback de vinculação fornecido (o "vinculador") aceita dois argumentos: o
// módulo pai (`bar` neste caso) e a string que é o especificador do
// módulo importado. O callback deve retornar um Módulo que
// corresponde ao especificador fornecido, com certos requisitos documentados
// em `module.link()`.
//
// Se a vinculação não tiver começado para o Módulo retornado, o mesmo callback
// de vinculação será chamado no Módulo retornado.
//
// Mesmo os Módulos de nível superior sem dependências devem ser explicitamente
// vinculados. O callback fornecido, no entanto, nunca seria chamado.
//
// O método link() retorna uma Promise que será resolvida quando todas as
// Promises retornadas pelo vinculador forem resolvidas.
//
// Nota: Este é um exemplo artificial, pois a função vinculador cria um novo
// módulo "foo" a cada vez que é chamada. Em um sistema de módulo completo, um
// cache provavelmente seria usado para evitar módulos duplicados.
async function linker(specifier, referencingModule) {
if (specifier === 'foo') {
return new vm.SourceTextModule(
`
// A variável "secret" se refere à variável global que adicionamos a
// "contextifiedObject" ao criar o contexto.
export default secret;
`,
{ context: referencingModule.context }
)
// Usar `contextifiedObject` em vez de `referencingModule.context`
// aqui também funcionaria.
}
throw new Error(`Não foi possível resolver a dependência: ${specifier}`)
}
await bar.link(linker)
// Etapa 3
//
// Avalie o Módulo. O método evaluate() retorna uma promise que será
// resolvida após o módulo terminar de ser avaliado.
// Imprime 42.
await bar.evaluate()
})()
module.dependencySpecifiers
Os especificadores de todas as dependências deste módulo. O array retornado é congelado para impedir quaisquer alterações nele.
Corresponde ao campo [[RequestedModules]]
dos registros de módulos cíclicos na especificação ECMAScript.
module.error
Se o module.status
for 'errored'
, esta propriedade contém a exceção lançada pelo módulo durante a avaliação. Se o status for diferente, acessar esta propriedade resultará em uma exceção lançada.
O valor undefined
não pode ser usado para casos em que não há uma exceção lançada devido à possível ambiguidade com throw undefined;
.
Corresponde ao campo [[EvaluationError]]
dos registros de módulos cíclicos na especificação ECMAScript.
module.evaluate([options])
options
<Object>timeout
<integer> Especifica o número de milissegundos para avaliar antes de terminar a execução. Se a execução for interrompida, umError
será lançado. Este valor deve ser um inteiro estritamente positivo.breakOnSigint
<boolean> Setrue
, receberSIGINT
(+) terminará a execução e lançará umError
. Os manipuladores existentes para o evento que foram anexados viaprocess.on('SIGINT')
são desabilitados durante a execução do script, mas continuam a funcionar depois disso. Padrão:false
.
Retorna: <Promise> Cumpre com
undefined
em caso de sucesso.
Avaliar o módulo.
Isso deve ser chamado depois que o módulo foi vinculado; caso contrário, ele será rejeitado. Pode ser chamado também quando o módulo já foi avaliado, caso em que ele não fará nada se a avaliação inicial terminar com sucesso (module.status
é 'evaluated'
) ou lançará novamente a exceção que a avaliação inicial resultou (module.status
é 'errored'
).
Este método não pode ser chamado enquanto o módulo está sendo avaliado (module.status
é 'evaluating'
).
Corresponde ao campo método concreto Evaluate() dos registros de módulos cíclicos na especificação ECMAScript.
module.identifier
O identificador do módulo atual, como definido no construtor.
module.link(linker)
[Histórico]
Versão | Alterações |
---|---|
v21.1.0, v20.10.0, v18.19.0 | A opção extra.assert foi renomeada para extra.attributes . O nome anterior ainda é fornecido para compatibilidade com versões anteriores. |
linker
<Function>specifier
<string> O especificador do módulo solicitado:referencingModule
<vm.Module> O objetoModule
em quelink()
é chamado.extra
<Object>attributes
<Object> Os dados do atributo: Conforme ECMA-262, espera-se que os hosts acionem um erro se um atributo não suportado estiver presente.assert
<Object> Alias paraextra.attributes
.Retorna: <vm.Module> | <Promise>
Retorna: <Promise>
Vincular dependências de módulos. Este método deve ser chamado antes da avaliação e só pode ser chamado uma vez por módulo.
A função deve retornar um objeto Module
ou uma Promise
que eventualmente se resolve para um objeto Module
. O Module
retornado deve satisfazer as duas invariantes a seguir:
- Deve pertencer ao mesmo contexto que o
Module
pai. - Seu
status
não deve ser'errored'
.
Se o status
do Module
retornado for 'unlinked'
, este método será chamado recursivamente no Module
retornado com a mesma função linker
fornecida.
link()
retorna uma Promise
que será resolvida quando todas as instâncias de vinculação se resolverem para um Module
válido, ou rejeitada se a função linker lançar uma exceção ou retornar um Module
inválido.
A função linker corresponde aproximadamente à operação abstrata HostResolveImportedModule definida pela implementação na especificação ECMAScript, com algumas diferenças importantes:
- A função linker pode ser assíncrona, enquanto HostResolveImportedModule é síncrona.
A implementação real de HostResolveImportedModule usada durante a vinculação do módulo é aquela que retorna os módulos vinculados durante a vinculação. Como nesse ponto todos os módulos já teriam sido totalmente vinculados, a implementação de HostResolveImportedModule é totalmente síncrona por especificação.
Corresponde ao campo método concreto Link() de Registros de Módulo Cíclicos na especificação ECMAScript.
module.namespace
O objeto namespace do módulo. Isso só está disponível após a conclusão do link (module.link()
).
Corresponde à operação abstrata GetModuleNamespace na especificação ECMAScript.
module.status
O status atual do módulo. Será um dos seguintes:
'unlinked'
:module.link()
ainda não foi chamado.'linking'
:module.link()
foi chamado, mas nem todas as Promises retornadas pela função de linkagem foram resolvidas ainda.'linked'
: O módulo foi vinculado com sucesso e todas as suas dependências estão vinculadas, masmodule.evaluate()
ainda não foi chamado.'evaluating'
: O módulo está sendo avaliado através demodule.evaluate()
em si mesmo ou em um módulo pai.'evaluated'
: O módulo foi avaliado com sucesso.'errored'
: O módulo foi avaliado, mas uma exceção foi lançada.
Além de 'errored'
, esta string de status corresponde ao campo [[Status]]
do Registro de Módulo Cíclico da especificação. 'errored'
corresponde a 'evaluated'
na especificação, mas com [[EvaluationError]]
definido como um valor que não é undefined
.
Classe: vm.SourceTextModule
Adicionado em: v9.6.0
[Estável: 1 - Experimental]
Estável: 1 Estabilidade: 1 - Experimental
Este recurso está disponível apenas com a flag de comando --experimental-vm-modules
ativada.
- Extende: <vm.Module>
A classe vm.SourceTextModule
fornece o Registro de Módulo de Texto de Origem conforme definido na especificação ECMAScript.
new vm.SourceTextModule(code[, options])
[Histórico]
Versão | Alterações |
---|---|
v17.0.0, v16.12.0 | Adicionou suporte para atributos de importação ao parâmetro importModuleDynamically . |
code
<string> Código do módulo JavaScript para análiseoptions
identifier
<string> String usada em rastros de pilha. Padrão:'vm:module(i)'
ondei
é um índice ascendente específico do contexto.cachedData
<Buffer> | <TypedArray> | <DataView> Fornece umBuffer
ouTypedArray
opcional, ouDataView
com os dados do cache de código do V8 para a fonte fornecida. Ocode
deve ser o mesmo que o módulo do qual estecachedData
foi criado.context
<Object> O objeto contextizado conforme retornado pelo métodovm.createContext()
, para compilar e avaliar esteModule
. Se nenhum contexto for especificado, o módulo será avaliado no contexto de execução atual.lineOffset
<integer> Especifica o deslocamento do número da linha que é exibido nos rastros de pilha produzidos por esteModule
. Padrão:0
.columnOffset
<integer> Especifica o deslocamento do número da coluna da primeira linha que é exibido nos rastros de pilha produzidos por esteModule
. Padrão:0
.initializeImportMeta
<Function> Chamado durante a avaliação desteModule
para inicializar oimport.meta
.meta
<import.meta>module
<vm.SourceTextModule>importModuleDynamically
<Function> Usado para especificar como os módulos devem ser carregados durante a avaliação deste módulo quandoimport()
é chamado. Esta opção faz parte da API experimental de módulos. Não recomendamos usá-la em um ambiente de produção. Para informações detalhadas, consulte Suporte deimport()
dinâmico em APIs de compilação.
Cria uma nova instância SourceTextModule
.
Propriedades atribuídas ao objeto import.meta
que são objetos podem permitir que o módulo acesse informações fora do context
especificado. Use vm.runInContext()
para criar objetos em um contexto específico.
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) {
// Nota: este objeto é criado no contexto superior. Como tal,
// Object.getPrototypeOf(import.meta.prop) aponta para o
// Object.prototype no contexto superior em vez daquele no
// objeto contextizado.
meta.prop = {}
},
})
// Como o módulo não tem dependências, a função de linkagem nunca será chamada.
await module.link(() => {})
await module.evaluate()
// Agora, Object.prototype.secret será igual a 42.
//
// Para corrigir este problema, substitua
// meta.prop = {};
// acima por
// 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) {
// Nota: este objeto é criado no contexto superior. Como tal,
// Object.getPrototypeOf(import.meta.prop) aponta para o
// Object.prototype no contexto superior em vez daquele no
// objeto contextizado.
meta.prop = {}
},
})
// Como o módulo não tem dependências, a função de linkagem nunca será chamada.
await module.link(() => {})
await module.evaluate()
// Agora, Object.prototype.secret será igual a 42.
//
// Para corrigir este problema, substitua
// meta.prop = {};
// acima por
// meta.prop = vm.runInContext('{}', contextifiedObject);
})()
sourceTextModule.createCachedData()
Adicionado em: v13.7.0, v12.17.0
- Retorna: <Buffer>
Cria um cache de código que pode ser usado com a opção cachedData
do construtor SourceTextModule
. Retorna um Buffer
. Este método pode ser chamado qualquer número de vezes antes do módulo ter sido avaliado.
O cache de código do SourceTextModule
não contém nenhum estado observável JavaScript. O cache de código pode ser salvo junto com a fonte do script e usado para construir novas instâncias SourceTextModule
múltiplas vezes.
Funções na fonte SourceTextModule
podem ser marcadas como compiladas preguiçosamente e não são compiladas na construção do SourceTextModule
. Essas funções serão compiladas quando forem invocadas pela primeira vez. O cache de código serializa os metadados que o V8 atualmente conhece sobre o SourceTextModule
que ele pode usar para acelerar compilações futuras.
// Cria um módulo inicial
const module = new vm.SourceTextModule('const a = 1;')
// Cria dados em cache a partir deste módulo
const cachedData = module.createCachedData()
// Cria um novo módulo usando os dados em cache. O código deve ser o mesmo.
const module2 = new vm.SourceTextModule('const a = 1;', { cachedData })
Classe: vm.SyntheticModule
Adicionado em: v13.0.0, v12.16.0
[Estável: 1 - Experimental]
Estável: 1 Estabilidade: 1 - Experimental
Este recurso está disponível apenas com o sinalizador de comando --experimental-vm-modules
ativado.
- Extende: <vm.Module>
A classe vm.SyntheticModule
fornece o Registro de Módulo Sintético conforme definido na especificação WebIDL. O objetivo dos módulos sintéticos é fornecer uma interface genérica para expor fontes não JavaScript a gráficos de módulos 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)
})
// Use `module` na ligação...
new vm.SyntheticModule(exportNames, evaluateCallback[, options])
Adicionado em: v13.0.0, v12.16.0
exportNames
<string[]> Array de nomes que serão exportados do módulo.evaluateCallback
<Function> Chamado quando o módulo é avaliado.options
identifier
<string> String usada em rastros de pilha. Padrão:'vm:module(i)'
ondei
é um índice ascendente específico do contexto.context
<Object> O objeto contextizado conforme retornado pelo métodovm.createContext()
, para compilar e avaliar esteModule
.
Cria uma nova instância SyntheticModule
.
Objetos atribuídos às exportações desta instância podem permitir que importadores do módulo acessem informações fora do context
especificado. Use vm.runInContext()
para criar objetos em um contexto específico.
syntheticModule.setExport(name, value)
Adicionado em: v13.0.0, v12.16.0
Este método é usado após o módulo ser vinculado para definir os valores das exportações. Se for chamado antes do módulo ser vinculado, um erro ERR_VM_MODULE_STATUS
será lançado.
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]])
[Histórico]
Versão | Alterações |
---|---|
v21.7.0, v20.12.0 | Adicionada a compatibilidade com vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v19.6.0, v18.15.0 | O valor retornado agora inclui cachedDataRejected com a mesma semântica que a versão vm.Script se a opção cachedData foi passada. |
v17.0.0, v16.12.0 | Adicionada a compatibilidade com atributos de importação ao parâmetro importModuleDynamically . |
v15.9.0 | A opção importModuleDynamically foi adicionada novamente. |
v14.3.0 | Remoção de importModuleDynamically devido a problemas de compatibilidade. |
v14.1.0, v13.14.0 | A opção importModuleDynamically agora é suportada. |
v10.10.0 | Adicionada em: v10.10.0 |
code
<string> O corpo da função a ser compilada.params
<string[]> Um array de strings contendo todos os parâmetros para a função.options
<Object>filename
<string> Especifica o nome do arquivo usado nos rastros de pilha produzidos por este script. Padrão:''
.lineOffset
<number> Especifica o offset do número da linha que é exibido nos rastros de pilha produzidos por este script. Padrão:0
.columnOffset
<number> Especifica o offset do número da coluna da primeira linha que é exibido nos rastros de pilha produzidos por este script. Padrão:0
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornece umBuffer
ouTypedArray
opcional, ouDataView
com os dados do cache de código do V8 para a fonte fornecida. Isso deve ser produzido por uma chamada anterior avm.compileFunction()
com o mesmocode
eparams
.produceCachedData
<boolean> Especifica se deve produzir novos dados de cache. Padrão:false
.parsingContext
<Object> O objeto contextizado em que a função mencionada deve ser compilada.contextExtensions
<Object[]> Um array contendo uma coleção de extensões de contexto (objetos que encapsulam o escopo atual) a serem aplicadas durante a compilação. Padrão:[]
.
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Usado para especificar como os módulos devem ser carregados durante a avaliação desta função quandoimport()
é chamado. Esta opção faz parte da API experimental de módulos. Não recomendamos usá-la em um ambiente de produção. Para informações detalhadas, consulte Suporte deimport()
dinâmico em APIs de compilação.Retorna: <Function>
Compila o código fornecido no contexto fornecido (se nenhum contexto for fornecido, o contexto atual é usado) e o retorna encapsulado em uma função com os params
fornecidos.
vm.constants
Adicionado em: v21.7.0, v20.12.0
Retorna um objeto contendo constantes comumente usadas para operações da VM.
vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER
Adicionado em: v21.7.0, v20.12.0
[Estável: 1 - Experimental]
Estável: 1 Estabilidade: 1.1 - Desenvolvimento ativo
Uma constante que pode ser usada como a opção importModuleDynamically
para vm.Script
e vm.compileFunction()
para que o Node.js use o carregador ESM padrão do contexto principal para carregar o módulo solicitado.
Para informações detalhadas, consulte Suporte de import()
dinâmico em APIs de compilação.
vm.createContext([contextObject[, options]])
[Histórico]
Versão | Alterações |
---|---|
v22.8.0, v20.18.0 | O argumento contextObject agora aceita vm.constants.DONT_CONTEXTIFY . |
v21.7.0, v20.12.0 | Adicionou suporte para vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v21.2.0, v20.11.0 | A opção importModuleDynamically agora é suportada. |
v14.6.0 | A opção microtaskMode agora é suportada. |
v10.0.0 | O primeiro argumento não pode mais ser uma função. |
v10.0.0 | A opção codeGeneration agora é suportada. |
v0.3.1 | Adicionada em: v0.3.1 |
contextObject
<Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> Ouvm.constants.DONT_CONTEXTIFY
ou um objeto que será contextizado. Seundefined
, um objeto contextizado vazio será criado para compatibilidade com versões anteriores.options
<Object>name
<string> Nome legível por humanos do contexto recém-criado. Padrão:'VM Context i'
, ondei
é um índice numérico crescente do contexto criado.origin
<string> Origem correspondente ao contexto recém-criado para fins de exibição. A origem deve ser formatada como uma URL, mas apenas com o esquema, host e porta (se necessário), como o valor da propriedadeurl.origin
de um objetoURL
. Mais notavelmente, esta string deve omitir a barra final, pois isso denota um caminho. Padrão:''
.codeGeneration
<Object>strings
<boolean> Se definido como falso, qualquer chamada paraeval
ou construtores de função (Function
,GeneratorFunction
, etc.) lançará umEvalError
. Padrão:true
.wasm
<boolean> Se definido como falso, qualquer tentativa de compilar um módulo WebAssembly lançará umWebAssembly.CompileError
. Padrão:true
.microtaskMode
<string> Se definido comoafterEvaluate
, microtarefas (tarefas programadas através dePromise
s easync function
s) serão executadas imediatamente após um script ter sido executado através descript.runInContext()
. Elas são incluídas nos escopostimeout
ebreakOnSigint
nesse caso.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Usado para especificar como os módulos devem ser carregados quandoimport()
é chamado neste contexto sem um script ou módulo de referência. Esta opção faz parte da API experimental de módulos. Não recomendamos usá-la em um ambiente de produção. Para informações detalhadas, consulte Suporte deimport()
dinâmico em APIs de compilação.
Retorna: <Object> objeto contextizado.
Se o contextObject
fornecido for um objeto, o método vm.createContext()
preparará esse objeto e retornará uma referência a ele para que possa ser usado em chamadas para vm.runInContext()
ou script.runInContext()
. Dentro desses scripts, o objeto global será encapsulado pelo contextObject
, retendo todas as suas propriedades existentes, mas também tendo os objetos e funções integrados que qualquer objeto global padrão possui. Fora dos scripts executados pelo módulo vm, as variáveis globais permanecerão inalteradas.
const vm = require('node:vm')
global.globalVar = 3
const context = { globalVar: 1 }
vm.createContext(context)
vm.runInContext('globalVar *= 2;', context)
console.log(context)
// Imprime: { globalVar: 2 }
console.log(global.globalVar)
// Imprime: 3
Se contextObject
for omitido (ou passado explicitamente como undefined
), um novo objeto contextizado vazio será retornado.
Quando o objeto global no contexto recém-criado é contextizado, ele apresenta algumas peculiaridades em comparação com objetos globais comuns. Por exemplo, ele não pode ser congelado. Para criar um contexto sem as peculiaridades de contextificação, passe vm.constants.DONT_CONTEXTIFY
como o argumento contextObject
. Consulte a documentação de vm.constants.DONT_CONTEXTIFY
para obter detalhes.
O método vm.createContext()
é principalmente útil para criar um único contexto que pode ser usado para executar vários scripts. Por exemplo, se estiver emulando um navegador da web, o método pode ser usado para criar um único contexto representando o objeto global de uma janela, e então executar todas as tags \<script\>
juntas dentro desse contexto.
O name
e a origin
fornecidos do contexto são tornados visíveis através da API do Inspector.
vm.isContext(object)
Adicionado em: v0.11.7
Retorna true
se o objeto object
fornecido foi contextizado usando vm.createContext()
, ou se é o objeto global de um contexto criado usando vm.constants.DONT_CONTEXTIFY
.
vm.measureMemory([options])
Adicionado em: v13.10.0
[Estável: 1 - Experimental]
Estável: 1 Estabilidade: 1 - Experimental
Mede a memória conhecida pelo V8 e usada por todos os contextos conhecidos pelo isolamento V8 atual, ou o contexto principal.
options
<Object> Opcional.mode
<string>'summary'
ou'detailed'
. No modo resumo, somente a memória medida para o contexto principal será retornada. No modo detalhado, a memória medida para todos os contextos conhecidos pelo isolamento V8 atual será retornada. Padrão:'summary'
execution
<string>'default'
ou'eager'
. Com a execução padrão, a promise não será resolvida até após o início da próxima coleta de lixo agendada, o que pode levar algum tempo (ou nunca, se o programa sair antes da próxima GC). Com a execução imediata, o GC será iniciado imediatamente para medir a memória. Padrão:'default'
Retorna: <Promise> Se a memória for medida com sucesso, a promise será resolvida com um objeto contendo informações sobre o uso da memória. Caso contrário, será rejeitada com um erro
ERR_CONTEXT_NOT_INITIALIZED
.
O formato do objeto com o qual a Promise retornada pode ser resolvida é específico do mecanismo V8 e pode mudar de uma versão do V8 para a próxima.
O resultado retornado difere das estatísticas retornadas por v8.getHeapSpaceStatistics()
no sentido de que vm.measureMemory()
mede a memória acessível por cada contexto específico do V8 na instância atual do mecanismo V8, enquanto o resultado de v8.getHeapSpaceStatistics()
mede a memória ocupada por cada espaço de heap na instância V8 atual.
const vm = require('node:vm')
// Mede a memória usada pelo contexto principal.
vm.measureMemory({ mode: 'summary' })
// Isso é o mesmo que vm.measureMemory()
.then(result => {
// O formato atual é:
// {
// total: {
// jsMemoryEstimate: 2418479, jsMemoryRange: [ 2418479, 2745799 ]
// }
// }
console.log(result)
})
const context = vm.createContext({ a: 1 })
vm.measureMemory({ mode: 'detailed', execution: 'eager' }).then(result => {
// Referencie o contexto aqui para que ele não seja coletado pelo GC
// até que a medição esteja completa.
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])
[Histórico]
Versão | Alterações |
---|---|
v21.7.0, v20.12.0 | Suporte adicionado para vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Suporte adicionado para atributos de importação ao parâmetro importModuleDynamically . |
v6.3.0 | A opção breakOnSigint agora é suportada. |
v0.3.1 | Adicionada em: v0.3.1 |
code
<string> O código JavaScript para compilar e executar.contextifiedObject
<Object> O objeto contextizado que será usado comoglobal
quando ocode
for compilado e executado.options
<Object> | <string>filename
<string> Especifica o nome do arquivo usado nos rastros de pilha produzidos por este script. Padrão:'evalmachine.\<anonymous\>'
.lineOffset
<number> Especifica o deslocamento do número da linha que é exibido nos rastros de pilha produzidos por este script. Padrão:0
.columnOffset
<number> Especifica o deslocamento do número da coluna da primeira linha que é exibido nos rastros de pilha produzidos por este script. Padrão:0
.displayErrors
<boolean> Quandotrue
, se umError
ocorrer durante a compilação docode
, a linha de código que causou o erro é anexada ao rastro de pilha. Padrão:true
.timeout
<integer> Especifica o número de milissegundos para executarcode
antes de terminar a execução. Se a execução for terminada, umError
será lançado. Este valor deve ser um inteiro estritamente positivo.breakOnSigint
<boolean> Setrue
, receberSIGINT
(+) terminará a execução e lançará umError
. Os manipuladores existentes para o evento que foram anexados viaprocess.on('SIGINT')
são desabilitados durante a execução do script, mas continuam a funcionar depois disso. Padrão:false
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornece umBuffer
ouTypedArray
, ouDataView
opcional com os dados do cache de código do V8 para a fonte fornecida.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Usado para especificar como os módulos devem ser carregados durante a avaliação deste script quandoimport()
é chamado. Esta opção faz parte da API experimental de módulos. Não recomendamos usá-la em um ambiente de produção. Para informações detalhadas, consulte Suporte deimport()
dinâmico em APIs de compilação.
O método vm.runInContext()
compila code
, executa-o no contexto do contextifiedObject
e retorna o resultado. A execução do código não tem acesso ao escopo local. O objeto contextifiedObject
deve ter sido previamente contextizado usando o método vm.createContext()
.
Se options
for uma string, então ele especifica o nome do arquivo.
O exemplo a seguir compila e executa scripts diferentes usando um único objeto contextizado:
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)
// Imprime: { globalVar: 1024 }
vm.runInNewContext(code[, contextObject[, options]])
[Histórico]
Versão | Alterações |
---|---|
v22.8.0, v20.18.0 | O argumento contextObject agora aceita vm.constants.DONT_CONTEXTIFY . |
v21.7.0, v20.12.0 | Adicionou suporte para vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Adicionou suporte para atributos de importação ao parâmetro importModuleDynamically . |
v14.6.0 | A opção microtaskMode agora é suportada. |
v10.0.0 | A opção contextCodeGeneration agora é suportada. |
v6.3.0 | A opção breakOnSigint agora é suportada. |
v0.3.1 | Adicionado em: v0.3.1 |
code
<string> O código JavaScript a ser compilado e executado.contextObject
<Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> Ouvm.constants.DONT_CONTEXTIFY
ou um objeto que será contextizado. Seundefined
, um objeto contextizado vazio será criado para compatibilidade com versões anteriores.filename
<string> Especifica o nome do arquivo usado nos rastros de pilha produzidos por este script. Padrão:'evalmachine.\<anonymous\>'
.lineOffset
<number> Especifica o deslocamento do número da linha que é exibido nos rastros de pilha produzidos por este script. Padrão:0
.columnOffset
<number> Especifica o deslocamento do número da coluna da primeira linha que é exibido nos rastros de pilha produzidos por este script. Padrão:0
.displayErrors
<boolean> Quandotrue
, se umError
ocorrer durante a compilação docode
, a linha de código que causou o erro é anexada ao rastro de pilha. Padrão:true
.timeout
<integer> Especifica o número de milissegundos para executarcode
antes de terminar a execução. Se a execução for terminada, umError
será lançado. Este valor deve ser um inteiro estritamente positivo.breakOnSigint
<boolean> Setrue
, receberSIGINT
(+) terminará a execução e lançará umError
. Os manipuladores existentes para o evento que foram anexados viaprocess.on('SIGINT')
são desabilitados durante a execução do script, mas continuam a funcionar depois disso. Padrão:false
.contextName
<string> Nome legível por humanos do contexto recém-criado. Padrão:'VM Context i'
, ondei
é um índice numérico ascendente do contexto criado.contextOrigin
<string> Origem correspondente ao contexto recém-criado para fins de exibição. A origem deve ser formatada como uma URL, mas apenas com o esquema, host e porta (se necessário), como o valor da propriedadeurl.origin
de um objetoURL
. Mais notavelmente, esta string deve omitir a barra final, pois isso denota um caminho. Padrão:''
.contextCodeGeneration
<Object>strings
<boolean> Se definido como false, qualquer chamada paraeval
ou construtores de função (Function
,GeneratorFunction
, etc.) lançará umEvalError
. Padrão:true
.wasm
<boolean> Se definido como false, qualquer tentativa de compilar um módulo WebAssembly lançará umWebAssembly.CompileError
. Padrão:true
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornece umBuffer
ouTypedArray
, ouDataView
opcional com os dados do cache de código do V8 para a fonte fornecida.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Usado para especificar como os módulos devem ser carregados durante a avaliação deste script quandoimport()
é chamado. Esta opção faz parte da API experimental de módulos. Não recomendamos usá-la em um ambiente de produção. Para informações detalhadas, consulte Suporte deimport()
dinâmico em APIs de compilação.microtaskMode
<string> Se definido comoafterEvaluate
, microtarefas (tarefas programadas por meio dePromise
s easync function
s) serão executadas imediatamente após a execução do script. Elas são incluídas nos escopostimeout
ebreakOnSigint
nesse caso.
Retorna: <any> o resultado da última instrução executada no script.
Este método é um atalho para (new vm.Script(code, options)).runInContext(vm.createContext(options), options)
. Se options
for uma string, ele especifica o nome do arquivo.
Ele faz várias coisas ao mesmo tempo:
O exemplo a seguir compila e executa código que incrementa uma variável global e define uma nova. Essas variáveis globais estão contidas no contextObject
.
const vm = require('node:vm')
const contextObject = {
animal: 'cat',
count: 2,
}
vm.runInNewContext('count += 1; name = "kitty"', contextObject)
console.log(contextObject)
// Imprime: { animal: 'cat', count: 3, name: 'kitty' }
// Isso lançaria uma exceção se o contexto fosse criado a partir de um objeto contextizado.
// vm.constants.DONT_CONTEXTIFY permite criar contextos com objetos globais comuns que
// podem ser congelados.
const frozenContext = vm.runInNewContext('Object.freeze(globalThis); globalThis;', vm.constants.DONT_CONTEXTIFY)
vm.runInThisContext(code[, options])
[Histórico]
Versão | Alterações |
---|---|
v21.7.0, v20.12.0 | Adicionou suporte para vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Adicionou suporte para atributos de importação ao parâmetro importModuleDynamically . |
v6.3.0 | A opção breakOnSigint agora é suportada. |
v0.3.1 | Adicionado em: v0.3.1 |
code
<string> O código JavaScript para compilar e executar.filename
<string> Especifica o nome do arquivo usado nos rastros de pilha produzidos por este script. Padrão:'evalmachine.\<anonymous\>'
.lineOffset
<number> Especifica o offset do número da linha que é exibido nos rastros de pilha produzidos por este script. Padrão:0
.columnOffset
<number> Especifica o offset do número da coluna da primeira linha que é exibido nos rastros de pilha produzidos por este script. Padrão:0
.displayErrors
<boolean> Quandotrue
, se umError
ocorrer durante a compilação docode
, a linha de código que causou o erro é anexada ao rastro de pilha. Padrão:true
.timeout
<integer> Especifica o número de milissegundos para executarcode
antes de terminar a execução. Se a execução for terminada, umError
será lançado. Este valor deve ser um inteiro estritamente positivo.breakOnSigint
<boolean> Setrue
, receberSIGINT
(+) terminará a execução e lançará umError
. Os manipuladores existentes para o evento que foram anexados viaprocess.on('SIGINT')
são desabilitados durante a execução do script, mas continuam a funcionar depois disso. Padrão:false
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornece umBuffer
ouTypedArray
opcional, ouDataView
com os dados do cache de código do V8 para a fonte fornecida.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Usado para especificar como os módulos devem ser carregados durante a avaliação deste script quandoimport()
é chamado. Esta opção faz parte da API experimental de módulos. Não recomendamos usá-la em um ambiente de produção. Para informações detalhadas, consulte Suporte deimport()
dinâmico em APIs de compilação.
Retorna: <any> o resultado da última declaração executada no script.
vm.runInThisContext()
compila code
, executa-o no contexto do global
atual e retorna o resultado. A execução do código não tem acesso ao escopo local, mas tem acesso ao objeto global
atual.
Se options
for uma string, então ele especifica o nome do arquivo.
O exemplo a seguir ilustra o uso de vm.runInThisContext()
e da função JavaScript eval()
para executar o mesmo código:
const vm = require('node:vm')
let localVar = 'valor inicial'
const vmResult = vm.runInThisContext('localVar = "vm";')
console.log(`vmResult: '${vmResult}', localVar: '${localVar}'`)
// Imprime: vmResult: 'vm', localVar: 'valor inicial'
const evalResult = eval('localVar = "eval";')
console.log(`evalResult: '${evalResult}', localVar: '${localVar}'`)
// Imprime: evalResult: 'eval', localVar: 'eval'
Como vm.runInThisContext()
não tem acesso ao escopo local, localVar
permanece inalterado. Em contraste, eval()
tem acesso ao escopo local, portanto o valor localVar
é alterado. Desta forma, vm.runInThisContext()
é muito parecido com uma chamada indireta de eval()
, por exemplo, (0,eval)('code')
.
Exemplo: Executando um servidor HTTP dentro de uma VM
Quando se usa script.runInThisContext()
ou vm.runInThisContext()
, o código é executado dentro do contexto global V8 atual. O código passado para este contexto da VM terá seu próprio escopo isolado.
Para executar um servidor web simples usando o módulo node:http
, o código passado para o contexto deve chamar require('node:http')
por si só, ou ter uma referência ao módulo node:http
passada a ele. Por exemplo:
'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('Servidor rodando em http://127.0.0.1:8124/');
})`
vm.runInThisContext(code)(require)
O require()
no caso acima compartilha o estado com o contexto de onde é passado. Isso pode introduzir riscos quando código não confiável é executado, por exemplo, alterando objetos no contexto de maneiras indesejadas.
O que significa "contextificar" um objeto?
Todo JavaScript executado dentro do Node.js roda dentro do escopo de um "contexto". De acordo com o Guia do Incorporador V8:
Quando o método vm.createContext()
é chamado com um objeto, o argumento contextObject
será usado para encapsular o objeto global de uma nova instância de um Contexto V8 (se contextObject
for undefined
, um novo objeto será criado a partir do contexto atual antes de sua contextificação). Este Contexto V8 fornece ao código
executado usando os métodos do módulo node:vm
um ambiente global isolado dentro do qual ele pode operar. O processo de criação do Contexto V8 e sua associação com o contextObject
no contexto externo é o que este documento se refere como "contextificar" o objeto.
A contextificação introduziria algumas peculiaridades ao valor globalThis
no contexto. Por exemplo, ele não pode ser congelado e não é referencialmente igual ao contextObject
no contexto externo.
const vm = require('node:vm')
// Uma opção `contextObject` indefinida torna o objeto global contextificado.
const context = vm.createContext()
console.log(vm.runInContext('globalThis', context) === context) // false
// Um objeto global contextificado não pode ser congelado.
try {
vm.runInContext('Object.freeze(globalThis);', context)
} catch (e) {
console.log(e) // TypeError: Cannot freeze
}
console.log(vm.runInContext('globalThis.foo = 1; foo;', context)) // 1
Para criar um contexto com um objeto global comum e obter acesso a um proxy global no contexto externo com menos peculiaridades, especifique vm.constants.DONT_CONTEXTIFY
como o argumento contextObject
.
vm.constants.DONT_CONTEXTIFY
Esta constante, quando usada como o argumento contextObject
nas APIs vm, instrui o Node.js a criar um contexto sem encapsular seu objeto global com outro objeto de maneira específica do Node.js. Como resultado, o valor globalThis
dentro do novo contexto se comportaria mais próximo de um comum.
const vm = require('node:vm')
// Use vm.constants.DONT_CONTEXTIFY para congelar o objeto 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
}
Quando vm.constants.DONT_CONTEXTIFY
é usado como o argumento contextObject
para vm.createContext()
, o objeto retornado é um objeto semelhante a um proxy para o objeto global no contexto recém-criado com menos peculiaridades específicas do Node.js. É igual por referência ao valor globalThis
no novo contexto, pode ser modificado de fora do contexto e pode ser usado para acessar elementos integrados no novo contexto diretamente.
const vm = require('node:vm')
const context = vm.createContext(vm.constants.DONT_CONTEXTIFY)
// O objeto retornado é igual por referência ao globalThis no novo contexto.
console.log(vm.runInContext('globalThis', context) === context) // true
// Pode ser usado para acessar variáveis globais no novo contexto diretamente.
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
// Pode ser congelado e isso afeta o contexto interno.
Object.freeze(context)
try {
vm.runInContext('baz = 1; baz;', context)
} catch (e) {
console.log(e) // Uncaught ReferenceError: baz is not defined
}
Interações de tempo limite com tarefas assíncronas e Promises
Promise
s e async function
s podem programar tarefas executadas pelo mecanismo JavaScript de forma assíncrona. Por padrão, essas tarefas são executadas depois que todas as funções JavaScript na pilha atual terminam de executar. Isso permite escapar da funcionalidade das opções timeout
e breakOnSigint
.
Por exemplo, o seguinte código executado por vm.runInNewContext()
com um tempo limite de 5 milissegundos agenda um loop infinito para ser executado após uma promise ser resolvida. O loop agendado nunca é interrompido pelo tempo limite:
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 })
// Isso é impresso *antes* de 'entering loop' (!)
console.log('done executing')
Isso pode ser resolvido passando microtaskMode: 'afterEvaluate'
para o código que cria o 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' }
)
Neste caso, a microtarefa programada por meio de promise.then()
será executada antes de retornar de vm.runInNewContext()
, e será interrompida pela funcionalidade de timeout
. Isso se aplica apenas ao código que está sendo executado em um vm.Context
, portanto, por exemplo, vm.runInThisContext()
não recebe esta opção.
Os callbacks de Promise são inseridos na fila de microtarefas do contexto em que foram criados. Por exemplo, se () =\> loop()
for substituído por apenas loop
no exemplo acima, então loop
será inserido na fila de microtarefas global, porque é uma função do contexto externo (principal), e, portanto, também poderá escapar do tempo limite.
Se as funções de programação assíncrona, como process.nextTick()
, queueMicrotask()
, setTimeout()
, setImmediate()
, etc., estiverem disponíveis dentro de um vm.Context
, as funções passadas a elas serão adicionadas a filas globais, que são compartilhadas por todos os contextos. Portanto, os callbacks passados para essas funções também não são controláveis pelo tempo limite.
Suporte de import()
dinâmico em APIs de compilação
As APIs a seguir suportam uma opção importModuleDynamically
para habilitar import()
dinâmico em código compilado pelo módulo vm
.
new vm.Script
vm.compileFunction()
new vm.SourceTextModule
vm.runInThisContext()
vm.runInContext()
vm.runInNewContext()
vm.createContext()
Esta opção ainda faz parte da API experimental de módulos. Não recomendamos seu uso em um ambiente de produção.
Quando a opção importModuleDynamically
não é especificada ou está indefinida
Se esta opção não for especificada, ou se estiver undefined
, o código contendo import()
ainda pode ser compilado pelas APIs vm
, mas quando o código compilado for executado e realmente chamar import()
, o resultado será rejeitado com ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING
.
Quando importModuleDynamically
é vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER
Esta opção não é atualmente suportada para vm.SourceTextModule
.
Com esta opção, quando um import()
é iniciado no código compilado, o Node.js usaria o carregador ESM padrão do contexto principal para carregar o módulo solicitado e retorná-lo ao código que está sendo executado.
Isso dá acesso aos módulos integrados do Node.js, como fs
ou http
, ao código que está sendo compilado. Se o código for executado em um contexto diferente, esteja ciente de que os objetos criados por módulos carregados do contexto principal ainda são do contexto principal e não são instanceof
classes integradas no novo contexto.
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 carregado do contexto principal não é uma instância da classe Function
// no novo contexto.
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 carregado do contexto principal não é uma instância da classe Function
// no novo contexto.
script.runInNewContext().then(console.log)
Esta opção também permite que o script ou função carregue módulos de usuário:
import { Script, constants } from 'node:vm'
import { resolve } from 'node:path'
import { writeFileSync } from 'node:fs'
// Escreve test.js e test.txt no diretório onde o script atual
// está sendo executado.
writeFileSync(resolve(import.meta.dirname, 'test.mjs'), 'export const filename = "./test.json";')
writeFileSync(resolve(import.meta.dirname, 'test.json'), '{"hello": "world"}')
// Compila um script que carrega test.mjs e depois test.json
// como se o script estivesse localizado no mesmo diretório.
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')
// Escreve test.js e test.txt no diretório onde o script atual
// está sendo executado.
writeFileSync(resolve(__dirname, 'test.mjs'), 'export const filename = "./test.json";')
writeFileSync(resolve(__dirname, 'test.json'), '{"hello": "world"}')
// Compila um script que carrega test.mjs e depois test.json
// como se o script estivesse localizado no mesmo diretório.
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)
Existem algumas ressalvas ao carregar módulos de usuário usando o carregador padrão do contexto principal:
Quando importModuleDynamically
é uma função
Quando importModuleDynamically
é uma função, ela será invocada quando import()
for chamado no código compilado para que os usuários personalizem como o módulo solicitado deve ser compilado e avaliado. Atualmente, a instância do Node.js deve ser iniciada com a flag --experimental-vm-modules
para que essa opção funcione. Se a flag não estiver definida, este callback será ignorado. Se o código avaliado realmente chamar import()
, o resultado será rejeitado com ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG
.
O callback importModuleDynamically(specifier, referrer, importAttributes)
tem a seguinte assinatura:
specifier
<string> especificador passado paraimport()
referrer
<vm.Script> | <Function> | <vm.SourceTextModule> | <Object> O referrer é ovm.Script
compilado paranew vm.Script
,vm.runInThisContext
,vm.runInContext
evm.runInNewContext
. É aFunction
compilada paravm.compileFunction
, ovm.SourceTextModule
compilado paranew vm.SourceTextModule
e o contextoObject
paravm.createContext()
.importAttributes
<Object> O valor"with"
passado para o parâmetro opcionaloptionsExpression
, ou um objeto vazio se nenhum valor foi fornecido.- Retorna: <Module Namespace Object> | <vm.Module> Retornar um
vm.Module
é recomendado para aproveitar o rastreamento de erros e evitar problemas com namespaces que contêm exportações de funçõesthen
.
// Este script deve ser executado com --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) // O script compilado
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' } }
// Este script deve ser executado com --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) // O script compilado
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' } }
})()