Загрузить и выполнить внешний файл js в node.js с доступом к локальным переменным?

130

Легко / возможно ли выполнить простой include('./path/to/file')тип команды в node.js?

Все, что мне нужно, - это иметь доступ к локальным переменным и запускать скрипт. Как люди обычно организуют проекты node.js, которые больше, чем просто привет мир? (Полнофункциональный динамический веб-сайт)

Например, я хотел бы иметь такие каталоги, как:

/models

/views

... и т.д

Travis
источник
Также возможно включить скрипт из внешнего URL (вместо локального файла). Смотрите здесь: pastebin.com/WkvHjGsG
Андерсон Грин
Приведенный выше сценарий работает правильно только в том случае, если вы создаете папку с именем downloadedModulesв том же каталоге, что и сценарий.
Андерсон Грин

Ответы:

134

Просто сделай require('./yourfile.js');

Объявите все переменные, к которым вы хотите получить доступ извне, как глобальные переменные. Так что вместо

var a = "hello" это будет

GLOBAL.a="hello" или просто

a = "hello"

Это явно плохо. Вы не хотите загрязнять глобальный масштаб. Вместо этого предлагается методexport ваших функций / переменных.

Если вам нужен шаблон MVC, взгляните на Geddy.

Шрипад Кришна
источник
3
В качестве примечания .. я люблю Экспресс. Вам тоже стоит это проверить, если вы не особо разбираетесь в MVC.
Shripad Krishna
43
Когда вы говорите «это явно плохо», что означает «это»?
Андерсон Грин
1
@AndersonGreen - он имеет в виду размещение переменных в глобальной области видимости.
Тим
77
@AndersonGreen: Пожалуйста, скажите мне, что это была очень умная шутка насчет определения объема работ ;-)
Dusty J
6
Это помогло мне узнать, что requireвыглядит в ваших модулях npm, если вы не укажете префикс пути чем-то вроде./
Дилан Валад
93

Вам нужно понимать CommonJS, который является шаблоном для определения модулей. Вы не должны злоупотреблять ГЛОБАЛЬНОЙ областью видимости, что всегда плохо, вместо этого вы можете использовать токен экспорта, например:

// circle.js

var PI = 3.14; // PI will not be accessible from outside this module

exports.area = function (r) {
  return PI * r * r;
};

exports.circumference = function (r) {
  return 2 * PI * r;
};

И клиентский код, который будет использовать наш модуль:

// client.js

var circle = require('./circle');
console.log( 'The area of a circle of radius 4 is '
           + circle.area(4));

Этот код был извлечен из API документации node.js:

http://nodejs.org/docs/v0.3.2/api/modules.html

Кроме того, если вы хотите использовать что-то вроде Rails или Sinatra, я рекомендую Express (я не смог опубликовать URL-адрес, позор за переполнение стека!)

Иван Торрес
источник
64

Если вы пишете код для Node, то использование модулей Node, как описано Иваном, без сомнения, лучший вариант.

Однако, если вам нужно загрузить уже написанный JavaScript, который не знает node, vmмодуль - это то, что вам нужно (и определенно предпочтительнее eval).

Например, вот мой execfileмодуль, который оценивает сценарий pathв любом contextили глобальном контексте:

var vm = require("vm");
var fs = require("fs");
module.exports = function(path, context) {
  var data = fs.readFileSync(path);
  vm.runInNewContext(data, context, path);
}

Также обратите внимание: загруженные модули require(…)не имеют доступа к глобальному контексту.

Дэвид Волевер
источник
1
Спасибо за этот совет. Реальный вариант использования - это когда вам нужно загрузить модули adhoc. Скажем, как шаблоны регистрации, где у вас будет 1000 модулей, которые регистрируются в центральной службе. Намного чище и удобнее сканировать модули и загружать их один за другим, а не делать 1000 запросов в вашей службе ...
Ассаф Молдавский
Node поддерживает динамические требования, поэтому нет причин использовать этот шаблон при динамической загрузке модулей с поддержкой Node. На самом деле, его использование здесь вредно, так как оно обходит Node require.cache, поэтому один файл может загружаться несколько раз.
Дэвид Уолевер
Итак, чтобы разрешить случай, который я представил, где у вас есть 1000 модулей, каждый из которых регистрируется в службе реестра, как вы использовать то, что вы предложили, не имея 1000 операторов require в службе реестра?
Ассаф Молдавский
1
Как requireобычно: function loadService(name) { return require('./services/' + name); }затем перечислите услуги, но это имеет смысл для приложения.
Дэвид Волевер
Верно, но это означает, что вы должны знать все 1000 модулей службы реестра. Что не лучше, чем иметь 1000 операторов require. Вся идея в том, что служба реестра не знает всех модулей и на самом деле заботится о них. Модули проходят специальную регистрацию в службе реестра. Имеет ли это смысл?
Ассаф Молдавский
7

Если вы планируете загрузить функции или объекты внешнего файла javascript, загрузите этот контекст, используя следующий код - обратите внимание на метод runInThisContext:

var vm = require("vm");
var fs = require("fs");

var data = fs.readFileSync('./externalfile.js');
const script = new vm.Script(data);
script.runInThisContext();

// here you can use externalfile's functions or objects as if they were instantiated here. They have been added to this context. 
Rox
источник
2
После долгих поисков и попыток эта техника сработала для меня. Мои файлы написаны для прямого использования браузером и объявления переменной, например: const aVar = {thing: 'a'}
lucsan
3

Расширяя ответы @Shripad и @Ivan , я бы порекомендовал вам использовать стандартные функции Node.js module.export .

В вашем файле для констант ( например constants.js ) вы должны написать такие константы:

const CONST1 = 1;
module.exports.CONST1 = CONST1;

const CONST2 = 2;
module.exports.CONST2 = CONST2;

Затем в файле, в котором вы хотите использовать эти константы, напишите следующий код:

const {CONST1 , CONST2} = require('./constants.js');

Если вы никогда раньше не видели const { ... }синтаксис: это деструктурирующее присваивание .

Джонатан Бенн
источник
0

Простите за воскрешение. Вы можете использовать модуль child_process для выполнения внешних файлов js в node.js

var child_process = require('child_process');

//EXECUTE yourExternalJsFile.js
child_process.exec('node yourExternalJsFile.js', (error, stdout, stderr) => {
    console.log(`${stdout}`);
    console.log(`${stderr}`);
    if (error !== null) {
        console.log(`exec error: ${error}`);
    }
});
lupu51nfactum N778
источник