simple-di
Install
$ npm install simple-di --save
Usage
Getting started is very simple. Just create a couple node modules, require simple-di, register your modules, and consume them at will.
See Basic Usage Example for a quick "Getting Started" example.
Currently, all modules registered with simple-di have a lifetime of 'app'. This means that any module will be instantiated once and only once, and will live until your process exits.
API
di.register(name, func)
Registers a module with the specified name, and uses the provided function as the constructor for the module instance.
The name of the module must be a valid Javascript identifier. However, it may be followed with a parenthesized list of "tags".
di.register("UserRepository (Repository, DatabaseModule)", function() {});
These tags can be used in a later call to getByTag.
simple-di assumes that all parameters to the function are dependencies, and will attempt to resolve them when creating the module's instance.
di.registerTransient(name, func)
Registers a transient module with the specified name, and uses the provided function as the constructor for the module instance.
A transient module is one that is instantiated every time it is needed, rather than a reusing a single application-wide instance.
di.get(name)
An instance of the module with the specified name will be returned.
di.getByTag(tag)
A map containing every module registered with the given tag will be returned. The map will contain name: instance
pairs for every module that matched the tag.
di.load(patterns, patterns_to_ignore)
Causes simple-di to load the specified files using require. Typically would be used one time during your app's startup routines to load all your modules, giving them a chance to register themselves with simple-di.
patterns - this is a glob string, or an array of glob strings to match against. The globs are matched using the path of the calling source file as the current working directory. Any file that matches one of these patterns (and does not match one of the patterns_to_ignore) will be loaded by simple-di.
patterns_to_ignore - this is a glob string, or an array of glob strings that should be ignored. Any files matching these patterns will not be loaded.
di.invoke(func)
Causes simple-di to invoke func, satisfying its dependencies via injection.
Provides an easy way to inject modules into a function, without needing to call di.get(name).
Error Scenarios
Basic Usage Example
constants.js
var di = require('simple-di');
di.register('Constants', function() {
this.pi = 3.14159;
});
circle.js
var di = require('simple-di');
di.register('Circle', function(Constants) {
this.area = function(radius) {
return Constants.pi * radius * radius;
};
});
app.js
var di = require('simple-di');
di.load(["**/*.js"], ["ignore_this_folder/**/*.js"]);
var circle = di.get('Circle');
console.log('A circle with a radius of 4 has an area of ' + circle.area(4));
Circular Dependency Example
Circular dependencies occur when a series of module dependencies contain a 'loop'.
If module A depends on module B, and B in turn depends on A, then you have a circular dependency. You will see an exception that looks like "Circular dependency found! A -> B -> A".
Here's an example:
A.js
var di = require('simple-di');
di.register('A', function(B) {
this.ping = function() {
return B.ping();
}
});
B.js
var di = require('simple-di');
di.register('B', function(A) {
this.ping = function() {
return A.ping();
}
});
app.js
var di = require('simple-di');
di.load("**/*.js");
var A = di.get('A');
console.log('This line will never be reached.');
In practical terms, you're more likely to hit this scenario with a dependency graph more complicated than this.
Often, there may be many modules in the list when you see a circular dependency exception. You might see something like "Circular dependency found! AccountService -> AccountRepository -> AccountValidator -> AccountService".
Let's imagine that this circular dependency was caused because AccountValidator needed the accountStatusTypes method from AccountService.
A new module called AccountHelper can be created, and the accountStatusType method can be moved there. Then, AccountValidator can be updated to depend on AccountHelper rather than AccountService, thus breaking the circular dependency.
The dependency graph would then look like AccountService -> AccountRepository -> AccountValidator -> AccountHelper". Additionally, AccountService would likely need to have AccountHelper added to its list of dependencies.
Unresolvable Dependency Example
Unresolvable dependencies occur when a module depends on another module which cannot be located by simple-di. You will see an exception that looks like "Could not resolve 'C'! A -> B -> C".
Here's an example:
A.js
var di = require('simple-di');
di.register('A', function(B) {
this.ping = B.ping;
});
B.js
var di = require('simple-di');
di.register('B', function(C) {
this.ping = C.ping;
});
app.js
var di = require('simple-di');
di.load("**/*.js");
var A = di.get('A');
console.log('This line will never be reached.');
Special parameters
"__Owner"
If a module is registered via registerTransient, it may depend upon a special parameter named __Owner. This parameter will be injected with the name of the module that requested the current transient instance of the module.