No Node.js, como faço para "incluir" funções dos meus outros arquivos?


968

Digamos que eu tenho 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 funções dentro de "tools.js". Como eu os importaria para usar no apps.js?

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


4
O que me impressionou aqui foi requireuma pasta no mesmo diretório do Windows. Você precisa usar o endereçamento no estilo unix: em ./mydirvez de simplesmente antigo mydir.
Ben

1
Criei um módulo para importar scripts, exportar para arquivo e incluir módulo da node_modulespasta externa . npmjs.com/package/node-import Espero que possa ajudar. Obrigado!
Nanang Mahdaen El-Agung 21/03/2015

Respostas:


1415

Você pode exigir qualquer arquivo js, ​​basta 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

101
+1 Muito bem, até limita o código importado ao seu próprio espaço para nome. Vou ter que anotar isso para mais tarde.
Evan Solha

8
Gostaria de saber se é possível importar scripts externos. require("http://javascript-modules.googlecode.com/svn/functionChecker.js")parece não importar o módulo corretamente. Existe alguma outra maneira de importar scripts externos?
Anderson Green

6
E se eu tenho que passar variável em função Como, bar: function (a, b) {// algum código}
Nishutosh Sharma

5
Como você está expondo propriedades, eu usaria exportações em vez de module.exports. Para exportações versus module.exports: stackoverflow.com/questions/5311334/…
Farm

4
como chamar bar () função, a função foo dentro (), meios de como acessar uma função withn outro
pitu

303

Se, apesar de todas as outras respostas, você ainda desejar incluir tradicionalmente um arquivo em um arquivo de origem node.js., você pode 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 objeto (você também pode usar, .toString()se preferir).
  • O eval () não pode ser usado dentro de uma função e deve ser chamado dentro do escopo global, caso contrário, nenhuma função ou variável estará acessível (ou seja, você não pode criar uma include()função utilitária ou algo parecido).

Observe que, na maioria dos casos, isso é uma prática ruim e você deve escrever um módulo . No entanto, existem situações raras, em que a poluição do seu contexto / espaço de nome local é o que você realmente deseja.

Atualização 06/08/2015

Observe também que isso não funcionará "use strict";(quando você estiver no "modo estrito" ) porque funções e variáveis definidas no arquivo "importado" não podem ser acessadas pelo código que importa. O modo estrito aplica 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.


41
Legal, isso é útil para colocar rapidamente libs JS projetadas para o lado do cliente em um aplicativo node.js. sem a necessidade de manter um fork no estilo Node.
Kos

18
Acabei de responder à pergunta original, que inclui incluir código e não escrever módulos. O primeiro pode ter vantagens em determinadas situações. Além disso, sua suposição sobre exigir está errada: o código certamente é avaliado, mas permanece em seu próprio espaço para nome e não tem como "poluir" o espaço para nome do contexto de chamada, portanto, você deve avaliar () você mesmo. Na maioria dos casos, usar o método descrito em minha resposta é uma prática ruim, mas não sou eu quem deve decidir se é para o TIMEX.
Udo G

14
@EvanPlaice: você tem uma sugestão melhor que realmente responda à pergunta ? Se você precisar incluir um arquivo que não seja um módulo , você tem uma abordagem melhor que essa?
jalf

8
Às vezes, quando você precisa incluir, e às vezes exige, eles são dois conceitos fundamentalmente diferentes na maioria das linguagens de programação, o Node JS também. A capacidade de incluir js no lugar deve fazer parte do Node para ser sincero, mas avaliar é essencialmente uma solução decente. Votado.
317 Martin

4
Note-se que é incompatível com o uso rigoroso - como utilização rigorosa vai restringir o uso de Eval bloqueando introdução de novas variáveis através Eval, etc
timbó

189

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 espaço para nome.

no tools.js

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

no app.js

ou em qualquer outro .js como myController.js:

ao invés de

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

podemos simplesmente ligar

require('tools.js')();

e depois

sum(1,2);

no meu caso, eu tenho um arquivo com os controladores ctrls.js

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

e eu posso usar Categoriesem todos os contextos como classe pública depoisrequire('ctrls.js')()


12
Como isso não tem mais +1? Esta é uma solução real para o que a pergunta faz (embora não seja a 'oficial'). Também é um milhão de vezes mais fácil de depurar do que eval () porque o nó pode fornecer uma pilha de chamadas útil, apontando para o arquivo real em vez de apenas indefinido.
user3413723

5
Observe que você não pode "usar o modo 'estrito" no módulo importado.
David David

1
@ Nick Panov: brilhante! Vale a pena notar que isso funciona porque thisem uma função é o escopo global quando a função é chamada diretamente (sem limite de forma alguma).
Udo G

3
isso acabou de mudar minha vida, não é brincadeira - tinha um arquivo de mais de 1000 linhas que eu não conseguia separar porque as variáveis ​​de métodos diferentes estão inter-correlacionadas e precisariam que os requisitos estivessem todos no mesmo escopo ... require('blah.js')(); deve permita-me importá-los todos no mesmo escopo !!! obrigado!!!
Sam Johnson

2
Esta é uma ótima dica! Advertência: se você declarar a função module.exports usando a sintaxe do atalho () => {} em vez da declaração da função padrão () {}, ela falhará. Levei uma hora para descobrir onde estava o problema! (As funções de seta não possuem sua própria propriedade 'this': developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
Ryan Griggs

117

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 do console

Value: 30

Qual versão do js funciona?
Mirv - Matt 25/03

39

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

Conteú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 () 
{
};

34

Eu também estava procurando uma função 'include' do NodeJS e verifiquei a solução proposta pelo 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.


2
Eu entendo o quão feio isso é, mas com certeza me ajudou.
Lindhe

30

crie dois arquivos, por exemplo, app.jsetools.js

app.js

const tools= require("./tools.js")


var x = tools.add(4,2) ;

var y = tools.subtract(4,2);


console.log(x);
console.log(y);

tools.js

 const add = function(x, y){
        return x+y;
    }
 const subtract = function(x, y){
            return x-y;
    }

    module.exports ={
        add,subtract
    }

resultado

6
2

26

dizer que quer chamar a função de ping () e adicionar (30,20) , que está em lib.js arquivo a partir 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
    }

1
Isso funciona, mas não devemos usar a sintaxe dos módulos ao incluir scripts?
Kokodoko 15/10/2015

25

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

Observe que, a partir de hoje, há um erro no módulo vm que previne que runInThisContext faça o que é certo quando invocado em 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. Consulte https://github.com/joyent/node/issues/898

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

Em resumo, aqui está uma função include () que funciona para mim:

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

Encontrei vm.runInThisContext em outra resposta do SO e a estava usando para incluir arquivos de código Javascript "vanilla". No entanto, tentei usá-lo para incluir código que dependia da funcionalidade do nó (por exemplo, "var fs = require ('fs')"), e não funcionou. Nesse caso, no entanto, as soluções "eval" observadas em algumas respostas realmente funcionam.
Dexygen

Pensando isso através de um pouco mais, quando você começa a necessidade de incluir o código que depende da funcionalidade nó, é provavelmente tempo para escrever um módulo, embora a solução eval poderia ser o primeiro passo nesse processo
Dexygen

Apenas um que trabalhou no node.js em 2019
meesern 9/10/19

13

Udo G. disse:

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

Ele está certo, mas há uma maneira de afetar o escopo global de uma função. Melhorando seu exemplo:

function include(file_) {
    with (global) {
        eval(fs.readFileSync(file_) + '');
    };
};

include('somefile_with_some_declarations.js');

// the declarations are now accessible here.

Espero que ajude.


12

Funcionou comigo como o seguinte ....

Lib1.js

//Any other private code here 

// Code you want to export
exports.function1 = function(params) {.......};
exports.function2 = function(params) {.......};

// Again any private code

agora no arquivo Main.js, você precisa incluir o Lib1.js

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

Lembre-se de colocar o Lib1.js na pasta node_modules .



11

Outra maneira de fazer isso, na minha opinião, é executar tudo no arquivo lib quando você chama a função require () using (function (/ * coisas aqui * /) {}) (); fazer isso tornará todas essas funções 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 por nome como:

main.js

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

Fará 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 :)


10

Eu só quero adicionar, caso você precise apenas de determinadas funções importadas do seu tools.js , você pode usar uma atribuição de desestruturação suportada no node.js desde a versão 6.4 - consulte 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));

resultado: true


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

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

para onde você precisa ligar tools.isEven(10).


NOTA:

Não se esqueça de prefixar o nome do arquivo com o caminho correto - mesmo se os dois arquivos estiverem na mesma pasta, você deverá prefixar ./

Dos documentos do Node.js :

Sem um '/', './' ou '../' à esquerda para indicar um arquivo, o módulo deve ser um módulo principal ou ser carregado a partir de uma pasta node_modules.


10

app.js

let { func_name } = require('path_to_tools.js');
func_name();    //function calling

tools.js

let func_name = function() {
    ...
    //function body
    ...
};

module.exports = { func_name };

3

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

2

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;

2

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

Criar 2 arquivos: fileread.jse fetchingfile.js, em seguida, fileread.jsescrever 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.jsescrever 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 argumento, além disso, inclua todos os arquivos em readfile.jsvez de passá-lo.

obrigado


2

Você pode simplesmente simples 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;

Observe que:

  1. você não pode ouvir PORT no arquivo filho, apenas o módulo pai Express tem ouvinte PORT
  2. A criança está usando 'Router', não o Express moudle principal.

1

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

O benefício é que você não polui o espaço para nome, não tenho problemas "use strict";e funciona bem.

Aqui está uma amostra completa :

Script a 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.


1

Outro método ao usar a estrutura node.js e express.js

var f1 = function(){
   console.log("f1");
}
var f2 = function(){
   console.log("f2");
}

module.exports = {
   f1 : f1,
   f2 : f2
}

armazene isso em um arquivo js chamado se na pasta static

Agora, para usar a função

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

1

Eu vim com um método bastante bruto de lidar com isso para modelagem de HTML. Similar ao PHP<?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>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>NodeJS Templated Page</title>
    <link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="/css/font-awesome.min.css">
    <!-- Scripts Load After Page -->
    <script type="text/javascript" src="/js/jquery.min.js"></script>
    <script type="text/javascript" src="/js/tether.min.js"></script>
    <script type="text/javascript" src="/js/bootstrap.min.js"></script>
</head>
<body>
    {{NAV}}
    <!-- Page Specific Content Below Here-->
</body>
</html>

navigation.html

<nav></nav>

Resultado da Página Carregada

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>NodeJS Templated Page</title>
    <link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="/css/font-awesome.min.css">
    <!-- Scripts Load After Page -->
    <script type="text/javascript" src="/js/jquery.min.js"></script>
    <script type="text/javascript" src="/js/tether.min.js"></script>
    <script type="text/javascript" src="/js/bootstrap.min.js"></script>
</head>
<body>
    <nav></nav>
    <!-- Page Specific Content Below Here-->
</body>
</html>

0

Se você quiser tirar proveito da arquitetura de múltiplas CPUs e microsserviços, para acelerar as coisas ... Use RPCs em processos bifurcados.

Parece complexo, mas é simples se você usar 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;
});

no 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í-o para um caso de uso semelhante, já que não consegui encontrar nenhuma biblioteca leve.


0

Para transformar "ferramentas" em um módulo, não vejo nada difícil. Apesar de todas as outras respostas, eu ainda recomendaria o uso do module.exports:

//util.js
module.exports = {
   myFunction: function () {
   // your logic in here
   let message = "I am message from myFunction";
   return message; 
  }
}

Agora, precisamos atribuir essas exportações ao escopo global (no seu aplicativo | index | server.js)

var util = require('./util');

Agora você pode consultar e chamar a função como:

//util.myFunction();
console.log(util.myFunction()); // prints in console :I am message from myFunction 

-3

Usar:

var mymodule = require("./tools.js")

app.js:

module.exports.<your function> = function () {
    <what should the function do>
}

1
Você quase nunca deve usar um diretório completo. Você deve considerar o uso de caminhos relativos como:./tools.js
Matthew D Auld
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.