n a
n a

Reputation: 2802

How to provide dependencies like db, logger, etc to an underlying library?

Setup

I'm building a base library for a distributed application. Here's the structure:

core_project/
    lib/
        index.js
        module1.js
        module2.js
        ...
    package.json

Many other parts of my application will use this library like this:

consumer_project/
    node_modules/
        core_project/
            ...
    app.js
    package.json

Problem

I want some common dependencies, like the DB handler to be provided by the consumer application. Once initialized, I want all my core application modules to be able to use those dependencies.

Attempted Solution

I attempted making an module initialization function in every core app module: core_project/lib/module1.js

var cfg = {db: null};

module.exports = {
    // ...
    'initModule': function (db) {
        cfg.db = db;
    }
}

And this is my core module index file: core_project/lib/index.js

var modules = {
    'module1': require('./module1'),
    'module1': require('./module2'),
    // ...
};

function create(db) {
    var app = {};
    init(app, modules, db);
    return app;
}

function init(app, mods, db) {
    var m;
    for (m in mods) {
        if (mods.hasOwnProperty(m)) {
            if (mods[m].hasOwnProperty('initModule')) {
                mods[m].initModule(db);
            }

            app[m] = mods[m];
        }
    }
}

module.exports = create;

Now, my consumer app can pass dependencies like this: consumer_project/app.js

var core = require('core_project');
var db = // initialize db

var app = core(db);

// Start using
app.module1.run();

Problems with attempted solution

  1. I have to add cfg = {db: null} and export the initModule function in every module that requires dependencies.
  2. I have to attach every module to the core app object in core_project/lib/index.js

Question

Is there a better way to provide consumer provided dependencies like db, logger to a core library and all its modules?

Upvotes: 2

Views: 115

Answers (1)

TheDeveloper
TheDeveloper

Reputation: 422

Passing in dependencies as arguments (i.e. dependency injection) is a perfectly valid way to achieve this, though you can simplify your init using a closure:

core_project/lib/module1.js:

module.exports = function(db) {
  return function() {
    // closure scoped with dependencies
    // can use db object
  };
}

Then your init function would create the closure:

app[m] = mods[m](db);

Passing deps like this is usually desirable for database clients so the same connection is used throughout your modules, however other types of deps like loggers might be better to import using the standard require() method of the module system e.g. require('winston')

Upvotes: 1

Related Questions