144

Is it possible to pass arguments when loading a module using require?

I have module, login.js which provides login functionality. It requires a database connection, and I want the same database connection to be used in all my modules. Now I export a function login.setDatabase(...) which lets me specify a database connection, and that works just fine. But I would rather pass the database and any other requirements when I load the module.

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

I am pretty new with NodeJS and usually develop using Java and the Spring Framework, so yes... this is a constructor injection :) Is it possible to do something like the code I provided above?

3
  • I'd also recommend looking at the answers to this question. As pointed out in my answer, a common idiom is to pass the app object to required modules. Commented Oct 31, 2012 at 5:39
  • Instead of doing all this argument passing for db, you could use a singleton implementation and call db.getInstance() where needed. Commented Nov 6, 2015 at 22:29
  • use db as an argument to the function inside your export file Commented Jun 1, 2021 at 6:55

3 Answers 3

254

Based on your comments in this answer, I do what you're trying to do like this:

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

I structure pretty much all my modules like that. Seems to work well for me.

Sign up to request clarification or add additional context in comments.

8 Comments

Is the app argument necessary or can I ommit it? My module won't make explicit use of this app argument, but I don't know if it is required by node.js for some internal thing. If it's ok, my module declaration would look like this: module.exports = function (db) {
That was specific to an Express app, so definitely not necessary.
@floatingLomas The serialization mechanism in python is called pickle: stackoverflow.com/questions/11218477/…
So what happens if you reference the module several times? The first require(mymodule)(myargs) would give you a module to work with. However if you reference it somewhere else from another module?? in the basic system there appears to be a cache involved, but in this system, the cache would return the bare generator method on subsequent calls to require(), and if you passed args to require()(someargs) you would get a different module back... maybe I am missing something
@TomH In that case, you'd want to cache it. To do that you'd have var module; outside the exports function, and then as soon as you come into the you'd want to check if module is already defined, and if so, just return it (and if not, initialize it). Does that make sense?
|
52

I'm not sure if this will still be useful to people, but with ES6 I have a way to do it that I find clean and useful.

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

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

And then you get your expected behaviour.

var MyClass = require('/MyClass.js')( arg1, arg2, arg3 )

1 Comment

How would this work using ES6 import (as opposed to require statements)?
34

Yes. In your login module, just export a single function that takes the db as its argument. For example:

module.exports = function(db) {
  ...
};

4 Comments

I tried this out. In login.js module.exports = function(app,db) { ... } module.exports.auth = function(req,res) { ... authentication stuff } It do call the "anonymous" function and sets the app and db variables, but, when doing this my application won't find the auth function. What am I doing wrong? If I remove the anonymous function the auth function becomes accessible again.
Like everything in javascript, exports is an object. You can assign properties to it (multiple exports), or you can assign it to a value. It sounds like you assigned exports to a function, but then assigned auth as a property of the function you assigned to exports. So you'd need to do var auth = require("./login.js").auth which may not be what you intended. If you want to use the pattern from the original question, its probably best to stick to a single export value. If this still does not make sense, I'd recommend posting a gist for me to look at.
After reading this again, it sounds like you may have assigned auth as a property of the exports object, and then later in the module you assigned exports to a function (thus overriding the previous assignment). If you reverse the order of the assignment you should be able to access the auth function as you'd expect. Again it's hard to tell without actually seeing the code.
Thanks alot for your help. What I didn't realize was exactly what you were aiming for with require('login').auth. I though there were no difference in var login = require('login') and var login = require('login')(app), but there is a huge difference, there is no magic in the anonymous function returned, it is just another function/object. Instead of having a module.exports.auth, the anomymous function now returns the auth function (amongs others), i.e. return { auth: authFunction, login: loginFunction}. So now it works. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.