Завантажити та виконати зовнішній 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.