No Node.js, como eu “incluo” funções dos meus outros arquivos?

Digamos que eu tenha um arquivo chamado app.js. Bem simples:

var express = require('express'); var app = express.createServer(); app.set('views', __dirname + '/views'); app.set('view engine', 'ejs'); app.get('/', function(req, res){ res.render('index', {locals: { title: 'NowJS + Express Example' }}); }); app.listen(8080); 

E se eu tiver uma function dentro de “tools.js”. Como eu iria importá-los para usar em apps.js?

Ou … eu deveria transformar “ferramentas” em um módulo e depois exigir isso? << parece difícil, prefiro fazer a importação básica do arquivo tools.js.

Você pode exigir qualquer arquivo js, ​​você só precisa declarar o que deseja expor.

 // tools.js // ======== module.exports = { foo: function () { // whatever }, bar: function () { // whatever } }; var zemba = function () { } 

E no seu arquivo de aplicativo:

 // app.js // ====== var tools = require('./tools'); console.log(typeof tools.foo); // => 'function' console.log(typeof tools.bar); // => 'function' console.log(typeof tools.zemba); // => undefined 

Se, apesar de todas as outras respostas, você ainda quiser include tradicionalmente um arquivo em um arquivo de origem node.js, poderá usar isto:

 var fs = require('fs'); // file is included here: eval(fs.readFileSync('tools.js')+''); 
  • A concatenação da string vazia +'' é necessária para obter o conteúdo do arquivo como uma string e não como um object (você também pode usar .toString() se preferir).
  • O eval () não pode ser usado dentro de uma function e deve ser chamado dentro do escopo global, caso contrário nenhuma function ou variável será acessível (ou seja, você não pode criar uma function de utilidade include() ou algo parecido).

Por favor, note que na maioria dos casos isso é uma má prática e você deve escrever um módulo . No entanto, existem situações raras, onde a poluição do seu contexto / espaço de nomes local é o que você realmente quer.

Atualização 2015-08-06

Por favor note também que isto não funcionará com "use strict"; (quando você está em “modo estrito” ) porque funções e variables definidas no arquivo “importado” não podem ser acessadas pelo código que faz a importação. O modo estrito impõe algumas regras definidas pelas versões mais recentes do padrão de idioma. Esse pode ser outro motivo para evitar a solução descrita aqui.

Você não precisa de novas funções nem novos módulos. Você simplesmente precisa executar o módulo que está chamando se não quiser usar o namespace.

em tools.js

 module.exports = function() { this.sum = function(a,b) { return a+b }; this.multiply = function(a,b) { return a*b }; //etc } 

em app.js

ou em qualquer outro .js como myController.js:

ao invés de

var tools = require('tools.js') que nos força a usar um namespace e chamar ferramentas como tools.sum(1,2);

nós podemos simplesmente ligar

 require('tools.js')(); 

e depois

 sum(1,2); 

no meu caso eu tenho um arquivo com controllers ctrls.js

 module.exports = function() { this.Categories = require('categories.js'); } 

e eu posso usar Categories em todos os contextos como public class depois de require('ctrls.js')()

Crie dois arquivos js

 // File cal.js module.exports = { sum: function(a,b) { return a+b }, multiply: function(a,b) { return a*b } }; 

Arquivo js principal

 // File app.js var tools = require("./cal.js"); var value = tools.sum(10,20); console.log("Value: "+value); 

Saída

 value: 30 

Aqui está uma explicação simples e clara:

Conteúdo do Server.js:

 // Include the public functions from 'helpers.js' var helpers = require('./helpers'); // Let's assume this is the data which comes from the database or somewhere else var databaseName = 'Walter'; var databaseSurname = 'Heisenberg'; // Use the function from 'helpers.js' in the main file, which is server.js var fullname = helpers.concatenateNames(databaseName, databaseSurname); 

Conteúdo do Helpers.js:

 // 'module.exports' is a node.JS specific feature, it does not work with regular JavaScript module.exports = { // This is the function which will be called in the main file, which is server.js // The parameters 'name' and 'surname' will be provided inside the function // when the function is called in the main file. // Example: concatenameNames('John,'Doe'); concatenateNames: function (name, surname) { var wholeName = name + " " + surname; return wholeName; }, sampleFunctionTwo: function () { } }; // Private variables and functions which will not be accessible outside this file var privateFunction = function () { }; 

Eu também estava procurando por uma function ‘include’ do NodeJS e verifiquei a solução proposta por Udo G – consulte a mensagem https://stackoverflow.com/a/8744519/2979590 . Seu código não funciona com meus arquivos JS incluídos. Finalmente resolvi o problema assim:

 var fs = require("fs"); function read(f) { return fs.readFileSync(f).toString(); } function include(f) { eval.apply(global, [read(f)]); } include('somefile_with_some_declarations.js'); 

Claro, isso ajuda.

O módulo vm no Node.js fornece a capacidade de executar o código JavaScript dentro do contexto atual (incluindo o object global). Consulte http://nodejs.org/docs/latest/api/vm.html#vm_vm_runinthiscontext_code_filename

Observe que, a partir de hoje, há um bug no módulo vm que impede que runInThisContext faça o direito quando chamado a partir de um novo contexto. Isso só importa se o seu programa principal executa o código dentro de um novo contexto e, em seguida, esse código chama runInThisContext. Veja https://github.com/joyent/node/issues/898

Infelizmente, a abordagem com (global) sugerida por Fernando não funciona para funções nomeadas como “function foo () {}”

Em suma, aqui está uma function include () que funciona para mim:

 function include(path) { var code = fs.readFileSync(path, 'utf-8'); vm.runInThisContext(code, path); } 

digamos que queremos chamar a function ping () e adicionar (30,20), que está no arquivo lib.js de main.js

main.js

 lib = require("./lib.js") output = lib.ping(); console.log(output); //Passing Parameters console.log("Sum of A and B = " + lib.add(20,30)) 

lib.js

 this.ping=function () { return "Ping Success" } 
 //Functions with parameters this.add=function(a,b) { return a+b } 

Udo G. disse:

  • O eval () não pode ser usado dentro de uma function e deve ser chamado dentro do escopo global, caso contrário nenhuma function ou variável será acessível (ou seja, você não pode criar uma function de utilidade include () ou algo parecido).

Ele está certo, mas há uma maneira de afetar o escopo global de uma function. Melhorando o exemplo dele:

 function include(file_) { with (global) { eval(fs.readFileSync(file_) + ''); }; }; include('somefile_with_some_declarations.js'); // the declarations are now accessible here. 

Espero que ajude.

Outra maneira de fazer isso, na minha opinião, é executar tudo no arquivo lib quando você chamar a function require () usando (function (/ * things here * /) {}) (); fazer isso fará com que todas essas funções sejam de escopo global, exatamente como a solução eval ()

src / lib.js

 (function () { funcOne = function() { console.log('mlt funcOne here'); } funcThree = function(firstName) { console.log(firstName, 'calls funcThree here'); } name = "Mulatinho"; myobject = { title: 'Node.JS is cool', funcFour: function() { return console.log('internal funcFour() called here'); } } })(); 

E então, no seu código principal, você pode chamar suas funções pelo nome como:

main.js

 require('./src/lib') funcOne(); funcThree('Alex'); console.log(name); console.log(myobject); console.log(myobject.funcFour()); 

Vai fazer essa saída

 bash-3.2$ node -v v7.2.1 bash-3.2$ node main.js mlt funcOne here Alex calls funcThree here Mulatinho { title: 'Node.JS is cool', funcFour: [Function: funcFour] } internal funcFour() called here undefined 

Preste atenção ao indefinido quando você chamar meu object.funcFour () , será o mesmo se você carregar com eval () . Espero que ajude 🙂

Você pode colocar suas funções em variables ​​globais, mas é melhor apenas transformar seu script de ferramentas em um módulo. Não é muito difícil – basta append sua API pública ao object de exports . Dê uma olhada no módulo Entendendo o Node.js para mais detalhes.

Funcionou comigo como o seguinte ….

Lib1.js

 //Any other private code here // Code you want to export exports.function1 = function1 (params) {.......}; exports.function2 = function2 (params) {.......}; // Again any private code 

agora no arquivo Main.js você precisa include Lib1.js

 var mylib = requires('lib1.js'); mylib.function1(params); mylib.function2(params); 

Por favor, lembre-se de colocar o Lib1.js na pasta node_modules .

Incluir arquivo e executá-lo em determinado contexto (não global)

fileToInclude.js

 define({ "data": "XYZ" }); 

main.js

 var fs = require("fs"); var vm = require("vm"); function include(path, context) { var code = fs.readFileSync(path, 'utf-8'); vm.runInContext(code, vm.createContext(context)); } // Include file var customContext = { "define": function (data) { console.log(data); } }; include('./fileToInclude.js', customContext); 

Eu só quero adicionar, caso você precise apenas de certas funções importadas de seu tools.js , então você pode usar uma atribuição de desestruturação que é suportada em node.js desde a versão 6.4 – veja node.green .


Exemplo : (os dois arquivos estão na mesma pasta)

tools.js

 module.exports = { sum: function(a,b) { return a + b; }, isEven: function(a) { return a % 2 == 0; } }; 

main.js

 const { isEven } = require('./tools.js'); console.log(isEven(10)); 

saída: true


Isso também evita que você atribua essas funções como propriedades de outro object como é o caso na seguinte atribuição (comum):

const tools = require('./tools.js');

onde você precisa chamar tools.isEven(10) .


NOTA:

Não esqueça de prefixar o nome do seu arquivo com o caminho correto – mesmo que ambos os arquivos estejam na mesma pasta, você precisa prefixar com ./

Dos documentos do Node.js :

Sem um ‘/’, ‘./’ ou ‘../’ para indicar um arquivo, o módulo deve ser um módulo central ou ser carregado de uma pasta node_modules.

Esta é a melhor maneira que eu criei até agora.

 var fs = require('fs'), includedFiles_ = {}; global.include = function (fileName) { var sys = require('sys'); sys.puts('Loading file: ' + fileName); var ev = require(fileName); for (var prop in ev) { global[prop] = ev[prop]; } includedFiles_[fileName] = true; }; global.includeOnce = function (fileName) { if (!includedFiles_[fileName]) { include(fileName); } }; global.includeFolderOnce = function (folder) { var file, fileName, sys = require('sys'), files = fs.readdirSync(folder); var getFileName = function(str) { var splited = str.split('.'); splited.pop(); return splited.join('.'); }, getExtension = function(str) { var splited = str.split('.'); return splited[splited.length - 1]; }; for (var i = 0; i < files.length; i++) { file = files[i]; if (getExtension(file) === 'js') { fileName = getFileName(file); try { includeOnce(folder + '/' + file); } catch (err) { // if (ext.vars) { // console.log(ext.vars.dump(err)); // } else { sys.puts(err); // } } } } }; includeFolderOnce('./extensions'); includeOnce('./bin/Lara.js'); var lara = new Lara(); 

Você ainda precisa informar o que deseja exportar

 includeOnce('./bin/WebServer.js'); function Lara() { this.webServer = new WebServer(); this.webServer.start(); } Lara.prototype.webServer = null; module.exports.Lara = Lara; 

Como você está tendo um arquivo abc.txt e muito mais?

Crie 2 arquivos: fileread.js e fetchingfile.js , em seguida, em fileread.js escreva este código:

 function fileread(filename) { var contents= fs.readFileSync(filename); return contents; } var fs = require("fs"); // file system //var data = fileread("abc.txt"); module.exports.fileread = fileread; //data.say(); //console.log(data.toString()); } 

Em fetchingfile.js escreva este código:

 function myerror(){ console.log("Hey need some help"); console.log("type file=abc.txt"); } var ags = require("minimist")(process.argv.slice(2), { string: "file" }); if(ags.help || !ags.file) { myerror(); process.exit(1); } var hello = require("./fileread.js"); var data = hello.fileread(ags.file); // importing module here console.log(data.toString()); 

Agora, em um terminal: $ node fetchingfile.js –file = abc.txt

Você está passando o nome do arquivo como um argumento, além disso, inclua todos os arquivos em readfile.js em vez de passá-lo.

obrigado

Você pode simples apenas require('./filename') .

Por exemplo.

 // file: index.js var express = require('express'); var app = express(); var child = require('./child'); app.use('/child', child); app.get('/', function (req, res) { res.send('parent'); }); app.listen(process.env.PORT, function () { console.log('Example app listening on port '+process.env.PORT+'!'); }); 
 // file: child.js var express = require('express'), child = express.Router(); console.log('child'); child.get('/child', function(req, res){ res.send('Child2'); }); child.get('/', function(req, res){ res.send('Child'); }); module.exports = child; 

Por favor note que:

  1. você não pode escutar PORT no arquivo filho, somente o módulo express pai tem ouvinte PORT
  2. Criança está usando ‘Router’, não pai Express moudle.

Eu também estava procurando uma opção para include código sem escrever módulos, resp. use as mesmas fonts independentes testadas de um projeto diferente para um serviço Node.js – e a resposta de jmparatte fez isso para mim.

O benefício é que você não polui o namespace, eu não tenho problemas com "use strict"; e funciona bem.

Aqui uma amostra completa :

Script para carregar – /lib/foo.js

 "use strict"; (function(){ var Foo = function(e){ this.foo = e; } Foo.prototype.x = 1; return Foo; }()) 

SampleModule – index.js

 "use strict"; const fs = require('fs'); const path = require('path'); var SampleModule = module.exports = { instAFoo: function(){ var Foo = eval.apply( this, [fs.readFileSync(path.join(__dirname, '/lib/foo.js')).toString()] ); var instance = new Foo('bar'); console.log(instance.foo); // 'bar' console.log(instance.x); // '1' } } 

Espero que isso tenha sido útil de alguma forma.

Outro método ao usar o node.js e o express.js framework

 var f1 = function(){ console.log("f1"); } var f2 = function(){ console.log("f2"); } module.exports = { f1 : f1, f2 : f2 } 

armazenar isso em um arquivo js chamado s e na pasta statics

Agora, para usar a function

 var s = require('../statics/s'); s.f1(); s.f2(); 

Eu criei um método bastante bruto de lidar com isso para modelos de HTML. Similar ao PHP < ?php include("navigation.html"); ?> Php < ?php include("navigation.html"); ?> < ?php include("navigation.html"); ?>

server.js

 var fs = require('fs'); String.prototype.filter = function(search,replace){ var regex = new RegExp("{{" + search.toUpperCase() + "}}","ig"); return this.replace(regex,replace); } var navigation = fs.readFileSync(__dirname + "/parts/navigation.html"); function preProcessPage(html){ return html.filter("nav",navigation); } var express = require('express'); var app = express(); // Keep your server directory safe. app.use(express.static(__dirname + '/public/')); // Sorta a server-side .htaccess call I suppose. app.get("/page_name/",function(req,res){ var html = fs.readFileSync(__dirname + "/pages/page_name.html"); res.send(preProcessPage(html)); }); 

page_name.html

 < !DOCTYPE html>     NodeJS Templated Page         {{NAV}}    

navigation.html

  

Resultado da Página Carregada

 < !DOCTYPE html>     NodeJS Templated Page             

Se você quiser aproveitar a arquitetura de várias CPUs e microsserviços, para agilizar as coisas … Use RPCs sobre processos bifurcados.

Soa complexo, mas é simples se você usa polvo .

Aqui está um exemplo:

em tools.js adicione:

 const octopus = require('octopus'); var rpc = new octopus('tools:tool1'); rpc.over(process, 'processRemote'); var sum = rpc.command('sum'); // This is the example tool.js function to make available in app.js sum.provide(function (data) { // This is the function body return data.a + data.b; }); 

em app.js, adicione:

 const { fork } = require('child_process'); const octopus = require('octopus'); const toolprocess = fork('tools.js'); var rpc = new octopus('parent:parent1'); rpc.over(toolprocess, 'processRemote'); var sum = rpc.command('sum'); // Calling the tool.js sum function from app.js sum.call('tools:*', { a:2, b:3 }) .then((res)=>console.log('response : ',rpc.parseResponses(res)[0].response)); 

Divulgação – Eu sou o autor do polvo, e construído para um caso similar, desde que eu não encontrei nenhuma biblioteca leve.