В Node.js, как мне "включить" функции из моих других файлов?

Допустим, у меня есть файл с именем app.js. Довольно просто:

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

Что делать, если у меня есть функции внутри "tools.js". Как бы я импортировал их для использования в apps.js?

Или... я должен превратить "инструменты" в модуль, а затем требовать его? << кажется сложным, я скорее делаю основной импорт файла tools.js.

31 ответ

Вам может потребоваться любой файл js, вам просто нужно объявить то, что вы хотите выставить.

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

var zemba = function () {
}

И в вашем файле приложения:

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

Если, несмотря на все остальные ответы, вы по-прежнему хотите традиционно включить файл в исходный файл node.js, вы можете использовать это:

var fs = require('fs');

// file is included here:
eval(fs.readFileSync('tools.js')+'');
  • Конкатенация пустой строки +'' необходимо получить содержимое файла в виде строки, а не объекта (вы также можете использовать .toString() Если вы предпочитаете).
  • Eval() не может использоваться внутри функции и должен вызываться внутри глобальной области видимости, иначе никакие функции или переменные не будут доступны (т.е. вы не можете создать include() функция полезности или что-то в этом роде).

Обратите внимание, что в большинстве случаев это плохая практика, и вы должны вместо этого написать модуль. Однако есть редкие ситуации, когда загрязнение вашего локального контекста / пространства имен - это то, что вы действительно хотите.

Обновление 2015-08-06

Пожалуйста, обратите внимание, что это не будет работать с "use strict"; (когда вы находитесь в "строгом режиме"), потому что функции и переменные, определенные в "импортированном" файле, не могут быть доступны для кода, который выполняет импорт. Строгий режим обеспечивает соблюдение некоторых правил, определенных новыми версиями языкового стандарта. Это может быть еще одной причиной, чтобы избежать решения, описанного здесь.

Вам не нужны ни новые функции, ни новые модули. Вам просто нужно выполнить модуль, который вы вызываете, если вы не хотите использовать пространство имен.

в tools.js

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

в app.js

или в любом другом.js, например, myController.js:

вместо

var tools = require('tools.js') что заставляет нас использовать пространство имен и вызывать такие инструменты, как tools.sum(1,2);

мы можем просто позвонить

require('tools.js')();

а потом

sum(1,2);

в моем случае у меня есть файл с контроллерами ctrls.js

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

и я могу использовать Categories в любом контексте, как общественный класс после require('ctrls.js')()

Создать два файла JS

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

Основной файл JS

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

Выход

value: 30

Попробуйте этот полный пример кода. Вы должны включить этот файл, используя require метод в app.js где вы хотите включить функции другого файла ex main.jsи этот файл должен предоставлять указанные функции, как в примере ниже.

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
}

выход

6
10

Вот простое и простое объяснение:

Содержание 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);

Содержание 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 () 
{
};

Я также искал функцию включения в NodeJS и проверил решение, предложенное Udo G - см. Сообщение /questions/44734171/v-nodejs-kak-mne-vklyuchit-funktsii-iz-moih-drugih-fajlov/44734308#44734308. Его код не работает с моими включенными JS-файлами. Наконец я решил проблему следующим образом:

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

Конечно, это помогает.

Создать два файла, например app.js а также standard_funcs.js

standard_funcs.js

 module.exports =
   {
        add,
        subtract
        // ...
    }


 function add(x, y){
        return x+y;
    }

 function subtract(x, y){
            return x-y;
    }
    

app.js

const sf= require("./standard_funcs.js")


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

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


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

    

выход

6
2

Скажем, мы хотим вызвать функцию ping() и добавить (30,20), которая находится в файле lib.js из 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
    }

Модуль vm в Node.js предоставляет возможность выполнять код JavaScript в текущем контексте (включая глобальный объект). См. http://nodejs.org/docs/latest/api/vm.html

Обратите внимание, что на сегодняшний день в модуле vm есть ошибка, которая не позволяет runInThisContext делать то же самое при вызове из нового контекста. Это имеет значение только в том случае, если ваша основная программа выполняет код в новом контексте, а затем этот код вызывает runInThisContext. См. https://github.com/joyent/node/issues/898

К сожалению, предложенный Фернандо подход with(global) не работает для именованных функций, таких как "function foo() {}"

Вкратце, вот функция include(), которая работает для меня:

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

Удо Г. сказал:

  • Eval() не может использоваться внутри функции и должен вызываться внутри глобальной области видимости, иначе никакие функции или переменные не будут доступны (т.е. вы не можете создать служебную функцию include() или что-то в этом роде).

Он прав, но есть способ повлиять на глобальную область видимости из функции. Улучшение своего примера:

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

include('somefile_with_some_declarations.js');

// the declarations are now accessible here.

Надеюсь, это поможет.

Это работало со мной как следующее....

Lib1.js

//Any other private code here 

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

// Again any private code

теперь в файле Main.js нужно включить Lib1.js

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

Пожалуйста, не забудьте поместить Lib1.js в папку node_modules.

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

По моему мнению, еще один способ сделать это - выполнить все в файле lib при вызове функции require() с помощью (function(/* вещи здесь */){})(); выполнение этого сделает все эти функции глобальной областью, точно так же как решение 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');
            }
    }
})();

И тогда в вашем основном коде вы можете вызывать ваши функции по имени, например:

main.js

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

Сделаю этот вывод

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

Обратите внимание на undefined, когда вы вызываете my object.funcFour (), это будет то же самое, если вы загрузите с помощью eval(). Надеюсь, поможет:)

Вы можете поместить свои функции в глобальные переменные, но лучше просто превратить ваш скрипт инструментов в модуль. Это на самом деле не так уж сложно - просто подключите ваш публичный API к exports объект. Взгляните на модуль экспорта в Understanding Node.js, чтобы узнать больше.

Я просто хочу добавить, если вам нужны только определенные функции, импортированные из вашего tools.js, тогда вы можете использовать назначение деструктурирования, которое поддерживается в node.js начиная с версии 6.4 - см. http://node.green/.


Пример:(оба файла находятся в одной папке)

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

выход: true


Это также позволяет избежать назначения этих функций в качестве свойств другого объекта, как в следующем (общем) назначении:

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

куда вам нужно позвонить tools.isEven(10),


НОТА:

Не забудьте указать префикс вашего имени файла с правильным путем - даже если оба файла находятся в одной папке, вам необходимо добавить префикс ./

Из документов Node.js:

Без начальных символов '/', './' или '../' для обозначения файла модуль должен быть основным модулем или загружаться из папки node_modules.

Использование модульной системы ESM:

a.js:

      export default function foo() {};

export function bar() {};

b.js:

      import foo, {bar} from './a.js';

Включить файл и запустить его в заданном (неглобальном) контексте

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

Как будто у вас есть файл abc.txt и еще много?

Создайте 2 файла: fileread.js а также fetchingfile.js, затем в 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());
}

В fetchingfile.js напишите этот код:

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

Теперь в терминале: $ node fetchingfile.js --file=abc.txt

Вы передаете имя файла в качестве аргумента, более того, включите все файлы в readfile.js вместо того, чтобы передать это.

Спасибо

Вы можете просто require('./filename'),

Например.

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

Обратите внимание, что:

  1. вы не можете прослушивать PORT для дочернего файла, только родительский экспресс-модуль имеет прослушиватель PORT
  2. Ребенок использует "Маршрутизатор", а не родительский экспресс moudle.

Это лучший способ, который я создал до сих пор.

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

Вам все еще нужно сообщить, что вы хотите экспортировать

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

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

Lara.prototype.webServer = null;

module.exports.Lara = Lara;

Самый чистый способ IMO заключается в следующем, в tools.js:

      function A(){
.
.
.
}

function B(){
.
.
.
}

module.exports = {
A,
B
}

Затем в app.js просто требуется tools.js следующим образом: const tools = require("tools");

Я хотел использовать статическую функцию и метод из класса JS. В противном случае я использую Typescript, но здесь это просто пост-скрипт после компиляции. До сих пор справились с этим самым сумасшедшим способом и сочетанием всех вышеперечисленных ответов:

js/tools.js:

      class Tools {
        count = 0;
    
        constructor(count) {
            this.count = count;
        }
    
        static add = function (x, y) { // static function
            return x + y;
        }
    
        incrementCountByValue(value) // instance method
        {
            this.count += value;
        }
    }
}

module.exports = {
    Tools
}

приложение.js:

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

console.log(Tools.add(2,2));// console output: 4

const tools = new Tools(5);
console.log(tools.count);// console output: 5

tools.incrementCountByValue(3);
console.log(tools.count); // console output: 8

Я придумал довольно грубый метод обработки этого для шаблонов HTML. Аналогично 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>

Результат загрузки страницы

<!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>

Node работает на основе модулей commonjs и, в последнее время, модулей esm. По сути, вы должны создавать модули в отдельных файлах .js и использовать импорт/экспорт (module.exports и require).

Javascript в браузере работает по-разному, в зависимости от области действия. Существует глобальная область видимости, и через clojures (функции внутри других функций) у вас есть частные области видимости.

Итак, в узле экспортируйте функции и объекты, которые вы будете использовать в других модулях.

Другой метод при использовании node.js и express.js framework

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

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

сохранить это в js-файле с именем s и в папке statics

Теперь использовать функцию

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

Я также искал возможность включить код без написания модулей, соответственно. использовать те же проверенные автономные источники из другого проекта для службы Node.js - и ответ jmparatte сделал это для меня.

Преимущество в том, что вы не загрязняете пространство имен, у меня нет проблем с "use strict"; и это работает хорошо.

Вот полный образец:

Скрипт для загрузки - /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'
    }

}

Надеюсь, это было как-то полезно.

Если вы хотите использовать преимущества нескольких процессоров и архитектуры микросервиса, чтобы ускорить процесс... Используйте RPC вместо разветвленных процессов.

Звучит сложно, но это просто, если вы используете осьминога.

Вот пример:

на tools.js добавьте:

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

в app.js добавьте:

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

Раскрытие - я автор осьминога, и создан для аналогичного варианта использования, так как я не мог найти легких библиотек.

Чтобы превратить "инструменты" в модуль, я не вижу ничего сложного. Несмотря на все остальные ответы, я все равно рекомендую использовать module.exports:

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

Теперь нам нужно назначить этот экспорт в глобальную область (в вашем приложении |index|server.js)

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

Теперь вы можете ссылаться и вызывать функцию как:

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

Для интерактивного тестирования модуля ./test.js в среде Unix можно использовать что-то вроде этого:

          >> node -e "eval(''+require('fs').readFileSync('./test.js'))" -i
    ...
Другие вопросы по тегам