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


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.


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!)


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.


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. 

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 .


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}`);
    }
});

Możesz skrócić if (error !== null)doif (error)
— GalaxyCat105
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.