npm package: @fnnwnchstr/di
Description: Dependency Injector
Author: Finn Winchester
Latest version: 0.7.0

# Dependency Injector
[![npm](https://img.shields.io/badge/npm-v0.6.0-BC443E.svg)](https://webpack.js.org)
[![Webpack](https://img.shields.io/badge/Webpack-4.26.0-81AEC8.svg)](https://webpack.js.org)
[![Babel](https://img.shields.io/badge/Babel-7.0.0-f5da55.svg)](https://babeljs.io)
[![Jest](https://img.shields.io/badge/Jest-23.6.0-99424f.svg)](https://jestjs.io)

## What is this?
This is a dependency injector meant to be used in whatever framework. It is framework agnostic so it will (or should) work with Angular, React, Vue, etc.

## Alright, now how can I use it?

1. Install the package from the npm registry:
```npm i -D @fnnwnchstr/di```

2. Import it. Obvious.
```import DependencyInjector from '@fnnwnchstr/di';```

3. Create the entry services file in the folder of your choice. It must export an empty JSON at least.
```export default {}```. This entry services file will be imported in your app's entry file.

4. In your app's entry file (main.js, index.js or whichever name you chose) you need to create a ```new``` of this Dependency Injector.
```const di = new DependencyInjector(name, services)```. You need to provide a ```name``` that will be the key to use it from your app.
This brand new dependency injector is attached to ```window``` so you can use it with ```window[name]``` or ```name``` directly.
5. Now you need to ```di.init()``` so it will load and create everything needed with the provided name and services.

6. Wherever in your app now you will be ready to use it as ```[name].get('service_name')```. It will create it on the fly if that service doesn't exist and then return it, or just return it if it already exists. Singleton patter, my friend.



## Great but now how can I declare my own services?
To add your services to that services file you will need to follow this structure:
```
import MyServiceClass from 'path/to/file';

{
    'service_name': {
        class: MyServiceClass
    }
}
```

```service_name``` will be the unique identifier for that service. We need to manually import it since we don't have any kind of autoloader.

#### Okay but this service has some dependencies...
If your service has (and will have) dependencies you can just improve the services file as follow:
```
import MyServiceClass from 'path/to/file';
import DependencyForMyService from 'path/to/other';

{
    'service_name': {
        class: MyServiceClass,
        with: ['@dependency_for_service']
    },
    'dependency_for_service': {
        class: DependencyForMyService
    }
}
```

We just added this ```with``` key to specify the dependencies this service will have. Here we can add as many dependencies as this service has. 3? Ok. 12? That's fine. 2000? Maybe you are doing anything wrong but it will work anyway.

##### Wait wait wait... why is starting with an @"?
Because it is a reference to specify that this thing is another service declared somewhere. Yes, we can have it splitted down in different files (and I personally recommend you so).

#### I am cool so far but what if the thing I need to inject has some static methods?
Alright, alright... Imagine again that we had that ```DependencyForMyService``` with a bunch of static methods. Then it's only about adding a ```tag``` field to the services file saying that it is ```is_static``` as follows.
```
import MyServiceClass from 'path/to/file';
import DependencyForMyService from 'path/to/other';

{
    'service_name': {
        class: MyServiceClass,
        with: ['@dependency_for_service']
    },
    'dependency_for_service': {
        class: DependencyForMyService,
        tags: ['is_static']
    }
}
```
Now instead of creating a ```new DependencyForMyService()``` the system will just inject the ```DependencyForMyService``` so the static methods will be available.

## Example
Let's imagine our services file has a service named ```common.utils```.
```
const di = new DependencyInjector('my_dependencies', services);
di.init();

# This will work
my_dependencies.get('common.utils');

# This will also work
window.my_dependencies.get('common.utils');

```

### Tips & Tricks
We must add this service entry file that will export all of the available services but if you want to split it down into several files you can do it as follows:
```
import MyModuleServices from 'path/to/module/services';
import MyOtherModuleServices from 'other/path/to/different/services';

export default {
    ...MyModuleServices,
    ...MyOtherModuleServices
}
```

And it will work as long as those files has the same structure detailed above.