web-dev-qa-db-fra.com

Dans Node.js, comment "inclure" des fonctions de mes autres fichiers?

Disons que j'ai un fichier appelé app.js. Assez simple:

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

Et si j'ai des fonctions dans "tools.js". Comment pourrais-je les importer pour les utiliser dans apps.js?

Ou ... suis-je censé transformer des "outils" en un module, puis en avoir besoin? << semble difficile, je préfère faire l'importation de base du fichier tools.js.

789
TIMEX

Vous pouvez exiger n'importe quel fichier js, il vous suffit de déclarer ce que vous voulez exposer.

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

var zemba = function () {
}

Et dans votre fichier d'application:

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

Si, malgré toutes les autres réponses, vous souhaitez toujours traditionnellement inclure un fichier dans un fichier source node.js, vous pouvez utiliser ceci:

var fs = require('fs');

// file is included here:
eval(fs.readFileSync('tools.js')+'');
  • La concaténation de chaîne vide +'' est nécessaire pour obtenir le contenu du fichier sous forme de chaîne et non d'objet (vous pouvez également utiliser .toString() si vous préférez).
  • Eval () ne peut pas être utilisé dans une fonction et doit être appelé dans la portée globale, sinon aucune fonction ou variable ne sera accessible (vous ne pouvez pas créer de fonction utilitaire include() ou quelque chose du genre).

Veuillez noter que dans la plupart des cas, il s'agit de mauvaise pratique et que vous devriez plutôt écrire un module . Cependant, il existe des situations rares où la pollution de votre contexte local/espace de noms est ce que vous voulez vraiment.

Mise à jour 2015-08-06

Notez également que cela ne fonctionnera pas avec "use strict"; (lorsque vous êtes en "mode strict" ) car les fonctions et les variables définies dans le fichier "importé" ne sont pas accessibles par le code qui fait l'importation. Le mode strict applique certaines règles définies par les versions les plus récentes du standard de langage. Ceci peut être une autre raison pour éviter la solution décrite ici.

279
Udo G

Vous n'avez besoin ni de nouvelles fonctions ni de nouveaux modules . Vous devez simplement exécuter le module que vous appelez si vous ne voulez pas utiliser d'espace de nom.

dans tools.js

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

dans app.js

ou dans tout autre fichier .js comme myController.js:

au lieu de

var tools = require('tools.js') qui nous oblige à utiliser un espace de noms et à appeler des outils comme tools.sum(1,2);

nous pouvons simplement appeler

require('tools.js')();

et alors

sum(1,2);

dans mon cas, j'ai un fichier avec les contrôleurs ctrls.js

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

et je peux utiliser Categories dans chaque contexte en tant que classe publique après require('ctrls.js')()

161
Nick Panov

Créer deux fichiers js

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

Fichier js principal

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

Sortie

value: 30
79
Jayaprakash G

Voici une explication simple et claire:

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

Contenu de 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 () 
{
};
39
Placeholder

Je recherchais également une fonction 'include' de NodeJS et j'ai vérifié la solution proposée par Udo G - voir le message https://stackoverflow.com/a/8744519/2979590 . Son code ne fonctionne pas avec mes fichiers JS inclus ..__ Enfin, j'ai résolu le problème de la manière suivante:

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

Bien sûr, ça aide.

32
jmparatte

Le module vm de Node.js permet d'exécuter du code JavaScript dans le contexte actuel (y compris l'objet global). Voir http://nodejs.org/docs/latest/api/vm.html#vm_vm_runinthiscontext_code_filename

Notez que, à ce jour, il existe un bogue dans le module vm qui empêche runInThisContext de faire le bon droit lorsqu'il est appelé depuis un nouveau contexte. Cela n'a d'importance que si votre programme principal exécute le code dans un nouveau contexte et que ce code appelle runInThisContext. Voir https://github.com/joyent/node/issues/898

Malheureusement, l'approche avec (globale) suggérée par Fernando ne fonctionne pas pour les fonctions nommées telles que "function foo () {}"

En bref, voici une fonction include () qui fonctionne pour moi:

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

disons que nous voulons appeler la fonction ping () et add (30,20) qui se trouve dans lib.js fichier depuis 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
    }
22
Dharmesh

Udo G. a déclaré: 

  • Eval () ne peut pas être utilisé dans une fonction et doit être appelé à l'intérieur la portée globale sinon aucune fonction ou variable ne sera accessible (c’est-à-dire que vous ne pouvez pas créer une fonction utilitaire include () ou quelque chose comme ça).

Il a raison, mais il y a un moyen d'affecter la portée globale d'une fonction. Améliorer son exemple:

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

include('somefile_with_some_declarations.js');

// the declarations are now accessible here.

J'espère que cela pourra aider.

13
Fernando

Une autre façon de faire cela, à mon avis, est d'exécuter tout dans le fichier lib quand vous appelez la fonction require () en utilisant (fonction (/ * choses ici * /) {}) (); faire cela rendra toutes ces fonctions globales, exactement comme la solution 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');
            }
    }
})();

Et ensuite, dans votre code principal, vous pouvez appeler vos fonctions par leur nom, par exemple:

main.js

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

Fera cette sortie

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

Faites attention au undefined lorsque vous appelez mon object.funcFour (), ce sera la même chose si vous chargez avec eval (). J'espère que ça aide :)

11
Alexandre Mulatinho

Vous pouvez placer vos fonctions dans des variables globales, mais il est préférable de simplement transformer votre script d’outils en un module. Ce n'est vraiment pas trop difficile - attachez simplement votre API publique à l'objet exports. Jetez un coup d'œil à Comprendre le module d'exportation de Node.js pour plus de détails.

9
Jimmy Cuadra

Essayez cet exemple de code complet. Vous devez inclure ce fichier à l'aide de la méthode require dans app.js où vous souhaitez inclure les fonctions d'un autre fichier ex main.js, et ce fichier doit exposer les fonctions spécifiées comme dans l'exemple ci-dessous.

app.js

const mainFile= require("./main.js")


var x = mainFile.add(2,4) ;
console.log(x);

var y =  mainFile.multiply(2,5); 
console.log(y);

main.js

const add = function(x, y){
    return x+y;
}
const multiply = function(x,y){
    return x*y;
}

module.exports ={
    add:add,
    multiply:multiply
}

sortie

6
10
6
YouBee

Cela a fonctionné avec moi comme suit .... 

Lib1.js

//Any other private code here 

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

// Again any private code

maintenant dans le fichier Main.js vous devez inclure Lib1.js

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

N'oubliez pas de placer le fichier Lib1.js dans le dossier node_modules .

6
M.Hefny

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 };
4
Ashish Duklan

Inclure le fichier et l'exécuter dans un contexte donné (non 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);
3
user11153

Vous pouvez simplement require('./filename').

Par exemple.

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

Veuillez noter que:

  1. vous ne pouvez pas écouter PORT sur le fichier enfant, seul le module parent express a un écouteur PORT
  2. L'enfant utilise 'Routeur', pas le parent Express moudle.
2
Weijing Lin

C'est la meilleure façon que j'ai créée jusqu'à présent.

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

Vous devez toujours indiquer ce que vous voulez exporter

includeOnce('./bin/WebServer.js');

function Lara() {
  this.webServer = new WebServer();
  this.webServer.start();
}

Lara.prototype.webServer = null;

module.exports.Lara = Lara;
2

Vous aimez avoir un fichier abc.txt et beaucoup plus? 

Créez 2 fichiers: fileread.js et fetchingfile.js, puis écrivez ce code dans fileread.js:

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

Dans fetchingfile.js, écrivez ce code:

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

Maintenant, dans un terminal: $ node fetchingfile.js --file = abc.txt

Vous transmettez le nom de fichier en tant qu'argument. De plus, incluez tous les fichiers dans readfile.js au lieu de le transmettre.

Merci

2
Gajender Singh

J'étais aussi à la recherche d'une option pour inclure du code sans écrire de modules, resp. utilisez les mêmes sources autonomes testées d'un projet différent pour un service Node.js - et la réponse de jmparatte l'a fait pour moi.

L'avantage est que vous ne polluez pas l'espace de noms, je n'ai pas de problème avec "use strict"; et cela fonctionne bien.

Voici un exemple complet:

Script à charger - /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'
    }

}

J'espère que cela a été utile en quelque sorte.

1
zyexal

Une autre méthode lors de l’utilisation de framework node.js et express.js

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

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

stocker ceci dans un fichier js nommé s et dans la statique du dossier

Maintenant pour utiliser la fonction

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

J'ai mis au point une méthode assez rudimentaire pour gérer cela pour les modèles HTML. De la même manière que 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));
});

nom_page.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>

Résultat de la page chargée

<!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>
1
Matthew D Auld

Si vous souhaitez tirer parti de l’architecture de plusieurs processeurs et microservices, accélérez les choses ... Utilisez des RPC par rapport aux processus définis.

Cela semble complexe, mais c'est simple si vous utilisez octopus .

Voici un exemple:

sur tools.js ajouter:

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

sur app.js, ajoutez:

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

divulgation - je suis l'auteur de poulpe, et construit si pour un cas d'utilisation similaire de la mienne, puisque je ne pouvais pas trouver de bibliothèques légères.

0
DhavalW

Pour transformer des "outils" en un module, je ne vois pas du tout mal. Malgré toutes les autres réponses, je recommanderais quand même l’utilisation de module.exports:

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

Maintenant, nous devons affecter ces exportations à la portée globale (dans votre application | index | server.js)

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

Maintenant, vous pouvez vous référer et appeler fonction comme:

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