Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a global variable in Node.js for dependency injection

I'm starting out a long term project, based on Node.js, and so I'm looking to build upon a solid dependency injection (DI) system.

Although Node.js at its core implies using simple module require()s for wiring components, I find this approach not best suited for a large project (e.g. requiring modules in each file is not that maintainable, testable or dynamic).

Now, I'd done my bits of research before posting this question and I've found out some interesting DI libraries for Node.js (see wire.js and dependable.js).

However, for maximal simplicity and minimal repetition I've come up with my own proposition of implementing DI:

  • You have a module, di.js, which acts as the container and is initialized by pointing to a JSON file storing a map of dependency names and their respective .js files. This already provides a dynamic nature to the DI, as you may easily swap test/development dependencies. The container can return dependencies by using an inject() function, which finds the dependency mapping and calls require() with it.

  • For simplicity, the module is assigned to a global variable, i.e. global.$di, so that any file in the project may use the container/injector by calling $di.inject().

Here's the gist of the implementation:

File di.js

module.exports = function(path) {

    this.deps = require(path);

    return {
        inject: function(name) {

                if (!deps[name])
                    throw new Error('dependency "' + name + '" isn\'t registered');
                return require(deps[name]);
        }
    };
};

Dependency map JSON file

{
    "vehicle": "lib/jetpack",
    "fuel": "lib/benzine",
    "octane": "lib/octane98"
}

Initialize the $di in the main JavaScript file, according to development/test mode:

var path = 'dep-map-' + process.env.NODE_ENV + '.json;
$di = require('di')(path);

Use it in some file:

var vehicle = $di.inject('vehicle');
vehicle.go();

So far, the only problem I could think of using this approach is the global variable $di. Supposedly, global variables are a bad practice, but it seems to me like I'm saving a lot of repetition for the cost of a single global variable.

What can be suggested against my proposal?

like image 583
ChenR Avatar asked Nov 01 '22 01:11

ChenR


1 Answers

Overall this approach sounds fine to me.

The way global variables work in Node.js is that when you declare a variable without the var keyword, and it gets added to the global object which is shared between all modules. You can also explicitly use global.varname. Example:

vehicle = "jetpack"
fuel = "benzine"
console.log(vehicle) // "jetpack"
console.log(global.fuel) // "benzine"

Variables declared with var will only be local to the module.

var vehicle = "car"
console.log(vehicle) // "car"
console.log(global.vehicle) // "jetpack"

So in your code if you are doing $di = require('di')(path) (without var), then you should be able to use it in other modules without any issues. Using global.$di might make the code more readable.

like image 179
mihai Avatar answered Nov 03 '22 17:11

mihai