Dioma

Elegant dependency injection container for vanilla JavaScript and TypeScrip...

README

Dioma


dioma

Elegant dependency injection container for vanilla JavaScript and TypeScript

Features


- Just do it - no decorators, no annotations, no magic- Tokens for class, value, and factory injection- Async injection and dependency cycle detection- TypeScript support- No dependencies- Tiny size

Installation


  1. ```sh
  2. npm install --save dioma

  3. yarn add dioma
  4. ```

Usage


To start injecting dependencies, you just need to add the static scope property to your class and use the inject function to get the instance of it. By default, inject makes classes "stick" to the container where they were first injected (more details in the Class registration section).

Here's an example of using it for Singleton and Transient scopes:

  1. ```typescript
  2. import { inject, Scopes } from "dioma";

  3. class Garage {
  4.   open() {
  5.     console.log("garage opened");
  6.   }

  7.   // Single instance of the class for the entire application
  8.   static scope = Scopes.Singleton();
  9. }

  10. class Car {
  11.   // injects instance of Garage
  12.   constructor(private garage = inject(Garage)) {}

  13.   park() {
  14.     this.garage.open();
  15.     console.log("car parked");
  16.   }

  17.   // New instance of the class on every injection
  18.   static scope = Scopes.Transient();
  19. }

  20. // Creates a new Car and injects Garage
  21. const car = inject(Car);

  22. car.park();
  23. ```

Scopes


Dioma supports the following scopes:

- Scopes.Singleton() - creates a single instance of the class
- Scopes.Transient() - creates a new instance of the class on every injection
- Scopes.Container() - creates a single instance of the class per container
- Scopes.Resolution() - creates a new instance of the class every time, but the instance is the same for the entire resolution
- Scopes.Scoped() is the same as Scopes.Container()

Singleton scope


Singleton scope creates a single instance of the class for the entire application.
The instances are stored in the global container, so anyone can access them.
If you want to isolate the class to a specific container, use the Container scope.

A simple example you can see in the Usage section.

Multiple singletons can be cross-referenced with each other using async injection.

Transient scope


Transient scope creates a new instance of the class on every injection:

  1. ```typescript
  2. import { inject, Scopes } from "dioma";

  3. class Engine {
  4.   start() {
  5.     console.log("Engine started");
  6.   }

  7.   static scope = Scopes.Singleton();
  8. }

  9. class Vehicle {
  10.   constructor(private engine = inject(Engine)) {}

  11.   drive() {
  12.     this.engine.start();
  13.     console.log("Vehicle driving");
  14.   }

  15.   static scope = Scopes.Transient();
  16. }

  17. // New vehicle every time
  18. const vehicle = inject(Vehicle);

  19. vehicle.drive();
  20. ```

Generally, transient scope instances can't be cross-referenced by the async injection with some exceptions.

Container scope


Container scope creates a single instance of the class per container. It's the same as the singleton, but relative to the custom container.

The usage is the same as for the singleton scope, but you need to create a container first and use container.inject instead of inject:

  1. ```typescript
  2. import { Container, Scopes } from "dioma";

  3. const container = new Container();

  4. class Garage {
  5.   open() {
  6.     console.log("garage opened");
  7.   }

  8.   // Single instance of the class for the container
  9.   static scope = Scopes.Container();
  10. }

  11. // Register Garage on the container
  12. container.register({ class: Garage });

  13. class Car {
  14.   // Use inject method of the container for Garage
  15.   constructor(private garage = container.inject(Garage)) {}

  16.   park() {
  17.     this.garage.open();
  18.     console.log("car parked");
  19.   }

  20.   // New instance on every injection
  21.   static scope = Scopes.Transient();
  22. }

  23. const car = container.inject(Car);

  24. car.park();
  25. ```

Container-scoped classes usually are registered in the container first. Without it, the class will "stick" to the container it's used in.