README
Dependency injection
Dependency injection with configuration and autowire for node js and browser (for example in combination with simq).
Imagine, that you have got some classes which are used very often. You have got two options: add instance of these classes to window object or to any other object, or create new instance every time when you want to use them.
The problem is that first solution add some "mess" to the window object and the other one is even more problematic. What if you will want to change for example constructor of this class (it's arguments) or call some methods right after class is instanced? Than you will have to change these setups at every place.
But with this package, you can configure your classes at one place and then let's just "ask" for them. (not service locator).
This package is inspired by dependency injection in Nette framework.
Help
Unfortunately I don't have any more time to maintain this repository :-(
Don't you want to save me and this project by taking over it?
Installation
$ npm install dependency-injection
Configuration
Please first read full documentation of easy-configuration. It will really help you.
{
"services": {
"application": {
"service": "path/to/my/application/module",
"arguments": ["./www", "someOtherVariable"],
"setup": {
"setApplicationName": ["nameOfApplication"],
"setSomethingOther": ["someUselessVariable", "andAnotherOne"]
}
}
}
}
There we set some application service with some arguments which will be given to constructor and some setup. Every time you will need this service, it will have got these arguments and all setup function will be called.
Section service is path for module require (common js).
You can of course use also modules from node_modules directory just like you are used to.
DI automatically look into values from setup in your module (service). If it is function, then it will be called, otherwise argument will be passed into this object property.
Usage
var DIFactory = require('dependency-injection/DIFactory');
var factory = new DIFactory('./path/to/your/configuration/file.json');
var di = factory.create();
Relative paths to config files are supported only on node (not in browser)!!!
This will create new instance of DI class which holding all your services.
You have to also set the basePath property. DI will prepend this basePath to all services' paths from your configuration. So it should be path to root directory of your application.
In example below, you can see how to get your services.
di.get('application');
di.create('application');
di.getFactory('application');
Base path to services
Base path is used for requiring your services. All services (exceptions are node_modules services) are relative to this path.
Default base path is directory in which is your config.json file.
di.basePath = __dirname + '/my/custom/base/directory';
Auto exposing into global
DI can be automatically exposed into window object (when on browser) or into global object (in node). Default name for
this object is di
.
{
"setup": {
"expose": true
}
}
Custom name:
{
"setup": {
"expose": "secondDI"
}
}
get
Some services may be "singleton" type (not really singleton but with one instance in whole application), which application service is clearly is.
This method will create one instance of service and store it. Every other time, this instance will be returned.
getByPath
Same as get
method, but this accepts path to node module (like in your service configuration)
create
Method create will just create new instance of service and will not store it.
getFactory
getFactory is almost the same like create method, but will return anonymous function, so if you then want to use it, you have to call it.
var application = di.getFactory('application');
application = application(); // just call it
Not instantiate services
When you want for example use jQuery as service, you will not want to automatically call something like new jquery
.
So you can tell DI, that this service will not be instantiate.
{
"services": {
"jquery": {
"service": "jquery"
"instantiate": false
}
}
}
Auto run services
When you are using configuration with json files, you can set some services to be started automatically after calling
the create
method.
{
"services": {
"setup": {
"service": "./path/to/setup",
"run": true
}
}
}
Autowiring
Accessing some DI object is not so pretty like we want, so there is some nice way how to avoid it. You can let DI to "inject" all your services to other. For example if your application service needs translator service, just let DI to give it to application.
All you need to do is add parameter "translator" to constructor of your application service. This name must be same like name of service in your configuration. DI then automatically give it translator service.
The same thing is also for methods. You don't have to configure them, just set name of needed service in method's arguments and DI will give you these services.
This is quite similar to dependency injection in angular.
Now in most cases you just have to use get
method just once for create instance of your base application service
and other services will be automatically injected.
Please, try to avoid circular dependencies (service A depends on service B and service B depends on service A).
Examples
In your configuration, you can use three dots as replacement for services.
Services:
var serviceA = function(serviceB, serviceC) { ... };
var serviceB = function(serviceC, namespace, item) { ... };
var serviceC = function(namespace, item, serviceD) { ... };
var serviceD = function() { ... };
Configuration:
{
"services": {
"serviceA": {
"service": "path/to/service/A",
"instantiate": false
},
"serviceB": {
"service": "path/to/service/B",
"arguments": ["...", "some namespace", "some item"],
"instantiate": false
},
"serviceC": {
"service": "path/to/service/C",
"arguments": ["some namespace", "some item"],
"instantiate": false
},
"serviceD": {
"service": "path/to/service/D",
"instantiate": false
}
}
}
or more expanded:
{
"services": {
"serviceA": {
"service": "path/to/service/A",
"arguments": ["..."],
"instantiate": false
},
"serviceB": {
"service": "path/to/service/B",
"arguments": ["...", "some namespace", "some item"],
"instantiate": false
},
"serviceC": {
"service": "path/to/service/C",
"arguments": ["some namespace", "some item", "..."],
"instantiate": false
},
"serviceD": {
"service": "path/to/service/D",
"arguments": ["..."],
"instantiate": false
}
}
}
Only problem is with minified javascript files which changes variable names. Solution for this is write some kind of hint for DI container.
var someFunction = function(otherNameForApplicationService) {
{'@di:inject': ['@application']}; // services' names are prepended with '@'
otherNameForApplicationService.run(); // this will call method run on service application
};
or you can also include services by their full paths:
var someFunction = function(otherNameForApplicationService) {
{'@di:inject': ['$path/to/application/service']}; // services' paths are prepended with '