Załadować i uruchomić zewnętrzny plik js w node.js z dostępem do zmiennych lokalnych?

136

Czy jest łatwe / możliwe wykonanie prostego include('./path/to/file')polecenia w node.js?

Chcę tylko mieć dostęp do zmiennych lokalnych i uruchomić skrypt. Jak ludzie zazwyczaj organizują projekty node.js, które są większe niż zwykły hello world? (W pełni funkcjonalna dynamiczna strona internetowa)

Na przykład chciałbym mieć katalogi takie jak:

/models

/views

... itd

Travis
źródło
Możliwe jest również dołączenie skryptu z zewnętrznego adresu URL (zamiast pliku lokalnego). Zobacz tutaj: pastebin.com/WkvHjGsG
Anderson Green,
Powyższy skrypt działa poprawnie tylko wtedy, gdy utworzysz folder o nazwie downloadedModulesw tym samym katalogu, co skrypt.
Anderson Green,

Odpowiedzi:

134

Po prostu zrób require('./yourfile.js');

Zadeklaruj wszystkie zmienne, do których chcesz mieć dostęp poza domeną, jako zmienne globalne. Więc zamiast

var a = "hello" To będzie

GLOBAL.a="hello" Lub tylko

a = "hello"

To jest oczywiście złe. Nie chcesz zanieczyszczać globalnego zasięgu. Zamiast tego metoda podpowiadania dotyczy exportfunkcji / zmiennych.

Jeśli chcesz mieć wzór MVC, spójrz na Geddy.

Shripad Krishna
źródło
3
Na marginesie ... uwielbiam Express. Powinieneś to również sprawdzić, pod warunkiem, że nie jesteś tak konkretny, jeśli chodzi o MVC.
Shripad Krishna
43
Kiedy mówisz „to jest oczywiście złe”, do czego się odnosi „to”?
Anderson Green,
1
@AndersonGreen - Ma na myśli umieszczanie zmiennych w zasięgu globalnym.
Tim
77
@AndersonGreen: Proszę, powiedz mi, że to był niezwykle sprytny żart na temat określania zakresu ;-)
Dusty J
6
Pomogło mi się nauczyć, że requirewygląda to w twoich modułach npm, jeśli nie poprzedzisz swojej ścieżki czymś w rodzaju./
Dylan Valade
96

Musisz zrozumieć CommonJS, który jest wzorcem do definiowania modułów. Nie powinieneś nadużywać zakresu GLOBALNEGO, co zawsze jest złe, zamiast tego możesz użyć tokena `` eksportu '', na przykład:

// 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;
};

Oraz kod klienta, który będzie korzystał z naszego modułu:

// client.js

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

Ten kod został wyodrębniony z interfejsu API dokumentacji node.js:

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

Ponadto, jeśli chcesz użyć czegoś takiego jak Rails lub Sinatra, polecam Express (nie mogłem opublikować adresu URL, szkoda Stack Overflow!)

Ivan Torres
źródło
65

Jeśli piszesz kod dla Node, użycie modułów Node w sposób opisany przez Ivana jest bez wątpienia najlepszym rozwiązaniem.

Jeśli jednak musisz załadować JavaScript, który został już napisany i nie jest świadomy istnienia węzła, vmmoduł jest drogą do zrobienia (i zdecydowanie lepiej eval).

Na przykład, oto mój execfilemoduł, który ocenia skrypt pathw dowolnym contextlub globalnym kontekście:

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

Uwaga: moduły załadowane require(…)nie mają dostępu do kontekstu globalnego.

David Wolever
źródło
1
Dziękuję za tę wskazówkę. Prawdziwy przypadek użycia ma miejsce, gdy trzeba załadować moduły adhoc. Powiedz jak wzorce rejestracji, w których miałbyś 1000 modułów rejestrujących się w centralnej usłudze. Znacznie czystszym i lepszym rozwiązaniem jest skanowanie w poszukiwaniu modułów i ładowanie ich jeden po drugim, zamiast wykonywania 1000 żądanych instrukcji ...
Assaf Moldavsky
Węzeł obsługuje dynamiczne wymagania, więc nie ma powodu, aby używać tego wzorca podczas dynamicznego ładowania modułów obsługujących węzeł. W rzeczywistości używanie tam jest aktywnie szkodliwe, ponieważ omija Node require.cache, więc pojedynczy plik może być ładowany wiele razy.
David Wolever
Ok, aby rozwiązać przypadek, który przedstawiłem, gdzie masz 1000 modułów, z których każdy rejestruje się w usłudze rejestru, jak możesz wykorzystać to, co zaproponowałeś, bez posiadania 1000 wymaganych oświadczeń w usłudze rejestru?
Assaf Moldavsky
1
Tak requirejak zwykle: function loadService(name) { return require('./services/' + name); }lista usług ma jednak sens dla aplikacji.
David Wolever
Zgadza się, ale to oznacza, że ​​musisz znać wszystkie 1000 modułów w usłudze rejestru. Co nie jest lepsze niż posiadanie 1000 wymagań. Cały pomysł polega na tym, że usługa rejestru nie zna wszystkich modułów i tak naprawdę dba o nie. Moduły rejestrują się ad hoc w usłudze rejestru. Czy to ma sens?
Assaf Moldavsky
7

Jeśli planujesz załadować funkcje lub obiekty zewnętrznego pliku javascript, załaduj ten kontekst za pomocą następującego kodu - zwróć uwagę na metodę 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
źródło
2
Po wielu poszukiwaniach i frobingu ta technika zadziałała dla mnie. Moje pliki są napisane dla przeglądarki do bezpośredniego użycia i deklarują zmienną, np .: const aVar = {rzecz: 'a'}
lucsan
3

Rozwijając odpowiedź @Shripad i @Ivan , polecam użycie standardowej funkcjonalności module.export Node.js.

W swoim pliku dla stałych ( np. constants.js ) Możesz zapisać stałe w ten sposób:

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

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

Następnie w pliku, w którym chcesz użyć tych stałych, napisz następujący kod:

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

Jeśli nigdy wcześniej nie widziałeś const { ... }składni: to jest destrukcyjne przypisanie .

Jonathan Benn
źródło
0

Przepraszam za zmartwychwstanie. Możesz użyć modułu child_process do wykonywania zewnętrznych plików js w 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
źródło
Możesz skrócić if (error !== null)doif (error)
GalaxyCat105