Carregar e executar o arquivo js externo no node.js com acesso a variáveis ​​locais?

130

É fácil / possível include('./path/to/file')executar um tipo simples de comando no node.js?

Tudo o que eu quero fazer é ter acesso a variáveis ​​locais e executar um script. Como as pessoas geralmente organizam projetos node.js. maiores que um simples mundo olá? (Um site dinâmico totalmente funcional)

Por exemplo, eu gostaria de ter diretórios como:

/models

/views

... etc

Travis
fonte
Também é possível incluir um script de uma URL externa (em vez de um arquivo local). Veja aqui: pastebin.com/WkvHjGsG
Anderson Verde
O script acima só funcionará corretamente se você criar uma pasta chamada downloadedModulesno mesmo diretório que o script.
Anderson Green

Respostas:

134

Basta fazer um require('./yourfile.js');

Declare todas as variáveis ​​que você deseja acesso externo como variáveis ​​globais. Então, ao invés de

var a = "hello" será

GLOBAL.a="hello" ou apenas

a = "hello"

Isso é obviamente ruim. Você não quer poluir o escopo global. Em vez disso, o método sugerido é para exportsuas funções / variáveis.

Se você deseja o padrão MVC, dê uma olhada no Geddy.

Shripad Krishna
fonte
3
Como uma nota lateral .. eu amo Express. Você também deve conferir, desde que não seja tão específico sobre o MVC.
Shripad Krishna
42
Quando você diz "isso é obviamente ruim", a que "isso" se refere?
Anderson Green
1
@AndersonGreen - Ele quer dizer colocar variáveis ​​no escopo global.
Tim
77
@AndersonGreen: Por favor, diga-me que era uma piada extremamente inteligente sobre o escopo ;-)
Dusty J
6
Ele me ajudou a aprender que os requireolhares em seus módulos NPM se você não prefixar o seu caminho com algo como./
Dylan Valade
93

Você precisa entender o CommonJS, que é um padrão para definir módulos. Você não deve abusar do escopo GLOBAL, que é sempre uma coisa ruim a se fazer; em vez disso, você pode usar o token 'export', assim:

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

E o código do cliente que usará nosso módulo:

// client.js

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

Este código foi extraído da API de documentação do node.js.

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

Além disso, se você quiser usar algo como Rails ou Sinatra, eu recomendo o Express (não consegui postar a URL, que vergonha no Stack Overflow!)

Ivan Torres
fonte
64

Se você estiver escrevendo código para o Node, usar os módulos do Node, conforme descrito por Ivan, é sem dúvida o caminho a percorrer.

No entanto, se você precisar carregar o JavaScript que já foi gravado e não está ciente do nó, o vmmódulo é o caminho a seguir (e definitivamente preferível eval).

Por exemplo, aqui está o meu execfilemódulo, que avalia o script pathem um contextou no contexto global:

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

Observe também: os módulos carregados com require(…)não têm acesso ao contexto global.

David Wolever
fonte
1
Obrigado por esta dica. O caso de uso real é quando você precisa carregar os módulos adhoc. Diga como um padrão de registro em que você teria 1000 módulos que se registram em um serviço central. É muito mais limpo e melhor design para procurar módulos e carregá-los um por um, em vez de fazer 1000 requerem declarações em seu serviço ...
Assaf Moldavsky
O nó suporta requisitos dinâmicos, portanto, não há razão para usar esse padrão ao carregar dinamicamente módulos compatíveis com o nó. De fato, é ativamente prejudicial usá-lo, uma vez que ignora os nós require.cache, portanto, um único arquivo pode ser carregado várias vezes.
David Wolever 17/08/16
Ok, então, para resolver o caso que apresentei em que você possui 1000 módulos em que cada um está se registrando em um serviço de registro, como você usa o que você propôs sem ter 1000 instruções requeridas no serviço de registro?
Assaf Moldavsky
1
Assim requirecomo o normal: function loadService(name) { return require('./services/' + name); }em seguida, listar os serviços no entanto faz sentido para a aplicação.
David Wolever
Certo, mas isso implica que você precisa conhecer todos os 1000 módulos no serviço de registro. O que não é melhor do que ter 1000 instruções requeridas. A idéia é que o serviço de registro não conheça todos os módulos e, de fato, se preocupe com eles. Os módulos registram ad hoc no serviço de registro. Isso faz sentido?
Assaf Moldavsky
7

Se você planeja carregar funções ou objetos de um arquivo javascript externo, carregue neste contexto usando o seguinte código - observe o método 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
fonte
2
Depois de muita pesquisa e agitação, essa técnica funcionou para mim. Meus arquivos são escritos para o navegador usar diretamente e declarar uma variável, por exemplo: const aVar = {thing: 'a'}
lucsan
3

Expandindo @Shripad 's e @Ivan resposta' s, eu recomendo que você use o padrão de Node.js module.export funcionalidade.

No seu arquivo para constantes ( por exemplo constants.js ), você escreveria constantes assim:

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

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

Em seguida, no arquivo em que você deseja usar essas constantes, escreva o seguinte código:

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

Se você nunca viu a const { ... }sintaxe antes: é uma tarefa de desestruturação .

Jonathan Benn
fonte
0

Desculpe pela ressurreição. Você poderia usar o módulo child_process para executar arquivos js externos no 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
fonte