js-winter v1.0.2
Dependency Inversion Framework for JavaScript
Introduction
js-winter is a lightweight highly performant dependency inversion framework built specifically to target JavaScript. It can be used to turn your application into a collection of loosely-coupled parts with highly segmented responsibilities. js-winter can then glue the parts together in many different configurations to allow you to easily write, re-use, refactor and test your code in a scalable and extremely flexible way.
This project is open source. You can find the official repository here.
Features
- Conditional binding (eg. by type, by name, etc.)
Installation
This is a Node.js module available through the npm registry.
Before installing, download and install Node.js.
If this is a brand new project, make sure to create a package.json
first with
the npm init
command.
Installation is done using the
npm install
command:
$ npm install js-winter
Table Of Contents
- Introduction
- What is Dependency Inversion?
- Theory
- js-winter API
- Hello World Example
- Binding
- Binding
- Constructor configuration
- What is Dependency Inversion?
Theory
In object-oriented design, the dependency inversion principle is a specific form of decoupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are reversed.
Hello World Example
const { serviceLocator } = require('js-winter');
class Greeter {
constructor() {
console.log('Hello World!');
}
}
// Binding
serviceLocator.bind('greeter', Greeter).asPrototype();
// Resolve
serviceLocator.get('greeter');
In this example, you are importing a locator service object. Bind the Greeter class by id and call its creation.
Binding
Every dependency injection framework is ultimately just a framework to bind types to instances.
In js-winter, dependency mapping is done by adding bindings to something called a container. The container should then 'know' how to create all the object instances in your application, by recursively resolving all dependencies for a given object.
Containers in this framework are implemented implicitly.
For example, given the following class:
class Greeter {
constructor() {
console.log('Hello World!');
}
}
You can wire up the dependencies for this class with the following:
serviceLocator.bind('greeter', Greeter).asPrototype();
// or
serviceLocator.bind('greeter', Greeter).asSingleton();
Container methods:
- asPrototype - Create via the JavaScript new operator. Sets lifecycle on the creation of new objects.
serviceLocator.bind('greeter', Greeter).asPrototype();
const greeter1 = serviceLocator.get('greeter');
const greeter2 = serviceLocator.get('greeter');
const result = greeter1 === greeter2; // false;
- asSingleton - Creates only one instance of an object. Sets the lifecycle like a singleton pattern.
serviceLocator.bind('greeter', Greeter).asSingleton();
const greeter1 = serviceLocator.get('greeter');
const greeter2 = serviceLocator.get('greeter');
const result = greeter1 === greeter2; // true;
Constructor configuration
If you need to configure an object from a container, you can pass the payload to the constructor.
Container method:
- withPayload - Passes the payload to the container and, when called get, passes them to the object's constructor.
class Greeter {
constructor(message) {
console.log(`Hello ${message}!`);
}
}
serviceLocator.bind('greeter', Greeter).asSingleton().withPayload('world');
//or
serviceLocator.bind('greeter', Greeter).withPayload('world').asSingleton();
serviceLocator.get('greeter');