Завантажити та виконати зовнішній js-файл у node.js з доступом до локальних змінних?


130

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

Все, що я хочу зробити - це отримати доступ до локальних змінних та запустити сценарій. Як люди зазвичай організовують проекти node.js, які перевищують простий світ привіт? (Повністю функціональний динамічний веб-сайт)

Наприклад, я хотів би мати каталоги типу:

/models

/views

... тощо


Також можна включити скрипт із зовнішньої URL-адреси (замість локального файлу). Дивіться тут: pastebin.com/WkvHjGsG
Anderson Green

Сценарій, описаний вище, працює правильно лише тоді, коли ви створюєте папку, що викликається downloadedModulesв тому самому каталозі, що і сценарій.
Андерсон Грін

Відповіді:


134

Просто зробіть require('./yourfile.js');

Декларуйте всі змінні, які потрібно зовнішнього доступу, як глобальні змінні. Тож замість

var a = "hello" це буде

GLOBAL.a="hello" або просто

a = "hello"

Це, очевидно, погано. Ви не хочете забруднювати глобальну сферу. Натомість запропонований метод відповідає exportвашим функціям / змінним.

Якщо ви хочете, щоб зразок MVC подивився на Гедді.


3
Як бічна примітка .. я люблю Експрес. Ви також повинні це перевірити за умови, якщо ви не такий конкретний щодо MVC.
Шріпад Кришна

42
Коли ви говорите «це очевидно погано», на що позначається «це»?
Андерсон Грін

1
@AndersonGreen - Він має на увазі розміщення змінних у глобальному масштабі.
Тим

77
@AndersonGreen: Скажіть, будь ласка, що це був надзвичайно спритний анекдот щодо скопірування ;-)
Dusty J

6
Це допомогло мені дізнатися, що requireвиглядає у ваших модулях npm, якщо ви не префіксуєте свій шлях чимось на кшталт./
Dylan Valade,

93

Вам потрібно зрозуміти CommonJS, що є шаблоном для визначення модулів. Ви не повинні зловживати сферою GLOBAL, що завжди погано робити, натомість ви можете використовувати маркер 'експортування', наприклад:

// 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-адрес, соромно на Stack Overflow!)


64

Якщо ви пишете код для Node, використання Node модулів, описаних Іваном, без сумніву, шлях.

Однак якщо вам потрібно завантажити JavaScript, який вже був написаний і не знає про вузол, 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 require.cache, тому один файл може завантажуватися кілька разів.
Девід Волвер

Гаразд, щоб вирішити випадок, який я представив, де у вас є 1000 модулів, де кожен реєструється в службі реєстру, як ви використовуєте те, що запропонували, не маючи 1000 записів на вимогу в службі реєстру?
Ассаф Молдавський

1
Як requireі звичайно: function loadService(name) { return require('./services/' + name); }тоді список служб має сенс для програми.
Девід Уолвер

Правильно, але це означає, що ви повинні знати всі 1000 модулів у службі реєстру. Що не краще, ніж мати 1000 заяв. Вся ідея полягає в тому, що служба реєстру не знає всіх модулів і насправді вона дбає про них. Модулі реєструють спеціальну службу реєстру. Чи має це сенс?
Ассаф Молдавський

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. 

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}`);
    }
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.