Передача аргументов в require (при загрузке модуля)

114

Можно ли передавать аргументы при загрузке модуля с помощью require?

У меня есть модуль login.js, который обеспечивает возможность входа в систему. Для этого требуется соединение с базой данных, и я хочу, чтобы одно и то же соединение с базой данных использовалось во всех моих модулях. Теперь я экспортирую функцию login.setDatabase (...), которая позволяет мне указать соединение с базой данных, и она отлично работает. Но я бы предпочел передать базу данных и любые другие требования при загрузке модуля.

var db = ...
var login = require("./login.js")(db);

Я новичок в NodeJS и обычно разрабатываю с использованием Java и Spring Framework, так что да ... это инъекция конструктора :) Можно ли сделать что-то вроде кода, который я предоставил выше?

Андреас Селенуолл
источник
Я также рекомендую посмотреть ответы на этот вопрос. Как указано в моем ответе, распространенная идиома - передать appобъект требуемым модулям.
Дэвид Уэлдон,
Вместо того, чтобы передавать все эти аргументы для db, вы можете использовать одноэлементную реализацию и вызывать db.getInstance () там, где это необходимо.
wulfgarpro

Ответы:

237

Основываясь на ваших комментариях в этом ответе , я делаю то, что вы пытаетесь сделать, вот так:

module.exports = function (app, db) {
    var module = {};

    module.auth = function (req, res) {
        // This will be available 'outside'.
        // Authy stuff that can be used outside...
    };

    // Other stuff...
    module.pickle = function(cucumber, herbs, vinegar) {
        // This will be available 'outside'.
        // Pickling stuff...
    };

    function jarThemPickles(pickle, jar) {
        // This will be NOT available 'outside'.
        // Pickling stuff...

        return pickleJar;
    };

    return module;
};

Я структурирую почти все свои модули таким образом. Кажется, у меня хорошо работает.

floatingLomas
источник
appНеобходим ли аргумент, или я могу его пропустить? Мой модуль не будет явно использовать этот аргумент приложения, но я не знаю, требуется ли он node.js для какой-то внутренней вещи. Если все в порядке, мое объявление модуля будет выглядеть так:module.exports = function (db) {
Улисс Алвес
Это было специфично для приложения Express, поэтому в этом нет необходимости.
floatingLomas
@floatingLomas Механизм сериализации в Python называется pickle: stackoverflow.com/questions/11218477/…
SadSeven,
1
Что же произойдет, если вы несколько раз обратитесь к модулю? Первый require(mymodule)(myargs)даст вам модуль для работы. Однако, если вы ссылаетесь на него где-то еще из другого модуля ?? в базовой системе, похоже, задействован кеш, но в этой системе кеш будет возвращать голый метод генератора при последующих вызовах require(), и если вы передадите аргументы, require()(someargs)вы получите обратно другой модуль ... возможно, мне не хватает something
Tom H
2
@TomH В этом случае вы захотите его кешировать. Для этого у вас будет var module;вне функции экспорта, а затем, как только вы войдете в moduleнее, вы захотите проверить, определена ли она, и если да, просто верните ее (а если нет, инициализируйте). Имеет ли это смысл?
floatingLomas
37

Я не уверен, что это все еще будет полезно для людей, но с ES6 у меня есть способ сделать это, который я считаю чистым и полезным.

class MyClass { 
  constructor ( arg1, arg2, arg3 )
  myFunction1 () {...}
  myFunction2 () {...}
  myFunction3 () {...}
}

module.exports = ( arg1, arg2, arg3 ) => { return new MyClass( arg1,arg2,arg3 ) }

И тогда вы получите ожидаемое поведение.

var MyClass = require('/MyClass.js')( arg1, arg2, arg3 )
вовкман
источник
32

Да. В вашем loginмодуле просто экспортируйте одну функцию, которая принимает в dbкачестве аргумента. Например:

module.exports = function(db) {
  ...
};
Дэвид Велдон
источник
1
Я попробовал это. В login.js module.exports = function(app,db) { ... } module.exports.auth = function(req,res) { ... authentication stuff } Это сделать вызов функции «анонимной» и устанавливает appи dbпеременные, но, при выполнении этого моего приложения не будет найти authфункцию. Что я делаю не так? Если я удалю анонимную функцию, authфункция снова станет доступной.
Андреас Селенуолл
Как и все в javascript, exportsэто объект. Вы можете назначить ему свойства (множественный экспорт) или присвоить ему значение. Похоже, вы назначили экспорт функции, но затем назначили auth как свойство функции, которую вы назначили экспорту. Так что вам нужно будет сделать var auth = require("./login.js").authто, что вы намеревались не делать. Если вы хотите использовать шаблон из исходного вопроса, вероятно, лучше всего придерживаться одного значения экспорта. Если это все еще не имеет смысла, я бы порекомендовал мне опубликовать суть.
Дэвид Уэлдон,
1
После повторного прочтения может показаться, что вы могли назначить его authв качестве свойства exportsобъекта, а затем в модуле, назначенном exportsфункции (таким образом, переопределив предыдущее назначение). Если вы измените порядок назначения, вы сможете получить доступ к authфункции, как и предполагали. Опять же, трудно сказать, не видя кода.
Дэвид Уэлдон,
1
Большое спасибо за твою помощь. То, что я не понимал, было именно тем, к чему вы стремились с помощью require ('login'). Auth. Хотя в var login = require('login')и нет разницы var login = require('login')(app), но разница огромная, в возвращаемой анонимной функции нет никакого волшебства, это просто еще одна функция / объект. Вместо того , чтобы иметь module.exports.auth, то anomymous функция теперь возвращает функцию аутентификации (amongs другие), то есть return { auth: authFunction, login: loginFunction}. Итак, теперь это работает. Спасибо.
Андреас Селенуолл