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

969

Допустим, у меня есть файл с именем 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.

TIMEX
источник
4
Что меня оттолкнуло, так это requireналичие папки в том же каталоге в Windows. Вы должны использовать адресацию в стиле Unix: ./mydirвместо простого старого mydir.
Бен
1
Я создал модуль для импорта сценариев, экспорта в файл и включения модуля из внешней node_modulesпапки. npmjs.com/package/node-import Надеюсь, что это может помочь. Спасибо!
Нананг Махдаен Эль-Агунг

Ответы:

1417

Вам может потребоваться любой файл 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
masylum
источник
101
+1 Отлично сделано, даже ограничивает импортированный код своим собственным пространством имен. Я должен сделать это к сведению на потом.
Эван Плейс
8
Интересно, можно ли импортировать внешние скрипты. require("http://javascript-modules.googlecode.com/svn/functionChecker.js")похоже, неправильно импортирует модуль. Есть ли другой способ импортировать внешние скрипты?
Андерсон Грин
6
А что если мне нужно передать переменную в функцию Like, bar: function (a, b) {// некоторый код}
Нишутош Шарма
5
Поскольку вы выставляете свойства, я бы использовал экспорт вместо module.exports. Для экспорта vs module.exports: stackoverflow.com/questions/5311334/…
Ферма
4
как вызвать функцию bar () внутри функции foo (), означает, как получить доступ к одной функции с помощью другой
pitu
303

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

var fs = require('fs');

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

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

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

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

Удо Г
источник
41
Круто, это полезно для быстрого и удобного размещения JS-библиотек, разработанных для клиентской части, в приложении node.js без необходимости поддерживать форк в стиле Node.
Кос
18
Я только что ответил на оригинальный вопрос, который касается включения кода, а не написания модулей. Первый может иметь преимущества в определенных ситуациях. Кроме того, ваше предположение о требовании неверно: код, безусловно, eval'd, но он остается в своем собственном пространстве имен и не имеет возможности «загрязнить» пространство имен вызывающего контекста, поэтому вам нужно самостоятельно выполнить eval (). В большинстве случаев использование метода, описанного в моем ответе, является плохой практикой, но не я должен решать, подходит ли он для TIMEX.
Удо G
14
@EvanPlaice: у вас есть лучшее предложение, которое на самом деле отвечает на вопрос ? Если вам нужно включить файл, который не является модулем , у вас есть лучший подход, чем этот?
Джалф
8
Иногда, когда вам нужно включить, а иногда и требуется, это два принципиально разных понятия в большинстве языков программирования, в том числе и в Node JS. Честно говоря, возможность включать js на месте должна быть частью Node, но, по сути, это достойное решение. Upvoted.
Дж. Мартин
4
Обратите внимание, что это несовместимо с использованием строгого - поскольку использование строгого ограничит использование eval, блокируя введение новых переменных через eval и т. Д.
timbo
189

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

в 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')()

Ник панов
источник
12
Как это не имеет больше +1? Это реальное решение того, что задает вопрос (хотя и не «официальный»). Это также в миллион раз легче отлаживать, чем eval (), потому что узел может дать полезный стек вызовов, вместо того, чтобы указывать на фактический файл вместо просто неопределенного.
user3413723
5
Обратите внимание, что вы не можете использовать «строгий» режим в импортированном модуле.
Дэвид
1
@ Ник Панов: великолепно! Стоит отметить, что это работает, потому что thisв функции есть глобальная область, когда функция вызывается напрямую (никак не связана).
Удо G
3
это просто изменил мою жизнь, не шутка - есть файл 1000+ линии , что я не мог разбить , поскольку переменные различных методов все взаимосвязаны коррелированы и нужно бы требует , чтобы быть все в том же объеме , ... require('blah.js')();должен позвольте мне импортировать их все в одну область !!! Спасибо!!!
Сэм Джонсон
2
Это отличный совет! Предупреждение: если вы объявляете функцию module.exports, используя синтаксис ярлыка () => {}, а не стандартное объявление function () {}, произойдет сбой. У меня ушел час, чтобы понять, в чем проблема! (Функции стрелок не имеют своего собственного свойства this: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
Райан Григгс,
117

Создать два файла 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
Джаяпракаш Г
источник
Какая версия JS это работает?
Мирв - Мэтт
39

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

Содержание 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 () 
{
};
Заполнитель
источник
34

Я также искал функцию включения в NodeJS и проверил решение, предложенное Udo G - см. Сообщение https://stackoverflow.com/a/8744519/2979590 . Его код не работает с моими включенными 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');

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

jmparatte
источник
2
Я понимаю, как это безобразно, но это точно помогло мне.
Линд
30

создать два файла, например app.js иtools.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
    }

вывод

6
2
YouBee
источник
26

говорю , что мы хотим вызвать функцию пинг () и добавить (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
    }
Dharmesh
источник
1
Это работает, но разве мы не должны использовать синтаксис модулей при включении скриптов?
Кокодоко
25

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

Обратите внимание, что на сегодняшний день в модуле 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);
}
Чад Остин
источник
Я нашел vm.runInThisContext в другом ответе SO и использовал его для включения «ванильных» файлов кода Javascript. Однако затем я попытался использовать его для включения кода, который зависел от функциональности узла (например, «var fs = require ('fs')»), и он не работал. В этом случае, однако, «eval» решение (я), отмеченное в нескольких ответах, действительно работает.
Кислород
Подумав об этом немного подробнее, когда вы начнете нуждаться в том, чтобы включать код, который зависит от функциональности узла, возможно, пришло время написать модуль, хотя решение eval может стать первым шагом в этом процессе
Dexygen
Только один, который работал в node.js в 2019 году
meesern
13

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

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

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

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

include('somefile_with_some_declarations.js');

// the declarations are now accessible here.

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

Фернандо
источник
12

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

Lib1.js

//Any other private code here 

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

// Again any private code

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

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

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

M.Hefny
источник
11

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

Джимми Куадра
источник
1
Пример лучше, чем ссылка
tno2007
11

По моему мнению, еще один способ сделать это - выполнить все в файле 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 () . Надеюсь, поможет :)

Александр Мулатино
источник
10

Я просто хочу добавить, что если вам нужны только определенные функции, импортированные из вашего tools.js , тогда вы можете использовать назначение деструктурирования, которое поддерживается в node.js начиная с версии 6.4 - см. 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.

Kristianmitk
источник
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

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

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);
user11153
источник
2

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

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;
Сауло Кастело Сампайо
источник
2

Как у вас есть файл 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 вместо того, чтобы передавать его.

Спасибо

Гаджендер Сингх
источник
2

Вы можете просто 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.
Вэйцзин Лин
источник
1

Я также искал возможность включить код без написания модулей, соответственно. использовать те же проверенные автономные источники из другого проекта для службы 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'
    }

}

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

zyexal
источник
1

Другой метод при использовании 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();
suku
источник
1

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

Если вы хотите использовать преимущества нескольких процессоров и микросервисной архитектуры, чтобы ускорить процесс ... Используйте 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));

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

DhavalW
источник
0

Чтобы превратить «инструменты» в модуль, я не вижу ничего сложного. Несмотря на все остальные ответы, я все равно рекомендую использовать 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 
StefaDesign
источник
-3

Использование:

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

app.js:

module.exports.<your function> = function () {
    <what should the function do>
}
кодировщик
источник
1
Вы почти никогда не должны использовать полный каталог. Вы должны рассмотреть возможность использования относительных путей, таких как:./tools.js
Мэтью Д. Олд