Выполнить js-код в отдельном контексте и получить доступ к его глобальной переменной

Я хотел бы запустить сторонний файл JavaScript (у меня нет большого контроля над его содержимым) в node и получить доступ к глобальной переменной, созданной этим файловым кодом в его контексте.

Есть две вещи, которые я рассмотрел:

  • Запуск кода в vm песочнице. Проблема в том, что я не знаю, как правильно создать контекст, потому что vm.createContext([sandbox]) не будет автоматически предоставлять основные вещи, такие как console или require или что-то еще в script, который я хочу запустить.

    Это немного облом, потому что в документации явно указано (внимание мое):

    Если задан объект песочницы, он будет "контекстуализировать" эту песочницу, чтобы ее можно было использовать в вызовах vm.runInContext() или script.runInContext(). Внутренние скрипты запускаются как таковые, песочница будет глобальным объектом, сохраняя все существующие свойства , но также имея встроенные объекты и функции любого стандартного глобального объекта.

    Что такое "встроенные объекты и функции любого стандартного глобального объекта"? Я наивно полагаю, что это такие вещи, как console, process, require и т.д. Но если так, API не работает, потому что они не установлены. Возможно, я что-то не понимаю.

    var sandbox = vm.createContext({foo: 'foo'});
    var code = 'console.log(foo);';
    vm.runInContext(code, sandbox);
    

    Результат:

    evalmachine.:1
    console.log(Foo);
    ^
    ReferenceError: консоль не определена

  • Выполнение кода в дочернем процессе . Но я не могу найти документацию о доступе к глобальным переменным дочерних процессов. Я предполагаю, что единственный способ общаться с дочерним процессом - это передача сообщения, но даже это кажется от родителя к ребенку, а не наоборот...

В принципе, я застрял. Halp.

Ответ 1

Вы можете использовать расширенный vm/песочницу для Node.js

var VM = require('vm2').NodeVM; // https://github.com/patriksimek/vm2#nodevm

var options = {
    console: 'inherit',
    sandbox: {
        foo: 'foo'
    }
}

vm = new VM(options);

var code = `
    console.log(foo); 
    oldFoo = foo; 
    foo = Math.random();
`;

vm.run(code);

console.log(vm.context.oldFoo, vm.context.foo);

Ответ 2

Как просто передать родительский console в контексте?

const vm = require('vm');

var sandbox = {
  console: console
};

var context = new vm.createContext(sandbox);
var script = new vm.Script('console.log("foo")');

script.runInContext(context);

Ответ 3

В этом коде мы можем отправить любой ответ и получить доступ к глобальной переменной с помощью глобальной функции, а также получить доступ ко всем данным, возвращаемым из VM Sandbox.

 function compiler(){
     let add = x*y
     Return (add);
 }
 compiler();

const vm = new NodeVM({
   sandbox: {
     Return(data) {
       console.log('Data:', data);
     },
     x : 10,=
     y : 20
   },
   require: {
     external: true,
     builtin: ["fs", "path"],
     root: "./",
     mock: {
       fs: {
         readFileSync() {
           return "Nice try!";
         }
       }
     }
   }
 });
 try {
   vm.run(req.query.code);
 } catch (error) {
   console.log("error: ", error);
 }