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




import header (16)

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

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 função 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.


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

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

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;

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 objeto como é o caso na seguinte atribuição (comum):

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

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

NOTA:

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

Dos documentos do Node.js :

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


Eu também estava procurando por uma função 'include' do NodeJS e verifiquei a solução proposta por Udo G - consulte a mensagem https://.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 objeto 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 () {}"

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

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

Outra maneira de fazer isso, na minha opinião, é executar tudo no arquivo lib quando você chamar a função require () usando (function (/ * things here * /) {}) (); 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 objeto.funcFour () , será o mesmo se você carregar com eval () . Espero que ajude :)


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

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

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 consegui encontrar nenhuma biblioteca leve.


Se, apesar de todas as outras respostas, você ainda quiser incluir 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 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 será acessível (ou seja, você não pode criar uma função 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 variáveis 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.


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 será 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 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.


Usar:

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

app.js:

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

Você pode colocar suas funções em variáveis ​​globais, mas é melhor apenas transformar seu script de ferramentas em um módulo. Não é muito difícil - basta anexar sua API pública ao objeto de exports . Dê uma olhada no módulo Compreender as exportações do Node.js para mais detalhes.


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

digamos que queremos chamar a função 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
    }

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




node.js