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?
node_modules? Other than that, the only thing your "DI" function is giving you is aliasing. I also think it is a misnomer to call this dependency injection. You have to ask for it each time explicitly, that makes it "dependency extraction" if anything. Finally,$diwon't be global - you'll need to do yourrequire('di')in every file or assign it to your node globals explicitly. If you are planning to use Express, you might findexpress-diof interest. Maybe I am misunderstanding something.var obj = require('some-module')(dependency1, dependency2);npm link. It appears mihai cleared up the globals thing. As I look at it this morning, I do think an adapted version of the direction you're taking is fine for having an easy way to switch out implementations in a single place via your dependency map file. FWIW, one of the good/bad things about Node is you have a lot of flexibility - if the strategy works for you, start with it. If you need to refactor down the road so be it, but it may work great. Good luck!