Skip to content

philip-bui/dagger

Repository files navigation

Dagger

Actions Status CodeCov npm Downloads

Declarative dependency injection for Javascript, inspired by Java's Dagger.

  • Declarative. Dagger makes it easy to read and build complex applications. Annotate dependencies, compose them and Dagger handles the wiring and injections.
  • Expressive. Few simple decorators, yet powerful. Use a minimalistic API extended by rich options chaining.
  • Interoperable. Adopt as little or as much dependency injection as you want. Dagger helps improve class cohesion, loose coupling and testability.

Installation

$ yarn add @dagger-js/core

Babel is used to compile decorators syntax and maintain compatibility with old JS environments. Add the class, properties and parameter decorator plugins.

$ yarn add -D @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties babel-plugin-parameter-decorator 
"plugins": [
    ["@babel/plugin-proposal-decorators", {"legacy": true}],
    ["@babel/plugin-proposal-class-properties", {"loose": true}],
    "babel-plugin-parameter-decorator"
]

If you're using ESLint (and you probably should!), add the babel-eslint parser to run on Babel compiled code.

$ yarn add -D babel-eslint
"eslintConfig": {
    "parser": "babel-eslint",
    "parserOptions": {
        "ecmaFeatures": {
            "legacyDecorators": true
        }
    },
}

Usage

import { Provides } from "@dagger-js/core";

@Provides
class FoodService {
    
    getFood = () => ["Apple"];
}
import { Singleton } from "@dagger-js/core";

@Singleton
class HeroService {

    getHeroes = () => ["Saitama"];
}
Constructor Injection

import { Inject, Named } from "@dagger-js/core";

@Inject
class HeroAcademcy {
    
    constructor(@Named("HeroService") heroService, water, @Named("FoodService") foodService) {
        this.heroes = heroService.getHeroes();
        this.water = water;
        this.food = foodService.getFood();
    }
}

const heroAcademy = new HeroAcademcy(undefined, ["Water"]);

console.log(heroAcademy.heroes); // ["Saitama"];
console.log(heroAcademy.water); // ["Water"];
console.log(heroAcademy.food); // ["Apple"];

Property Injection

import { Inject } from "@dagger-js/core";
import HeroService from "./HeroService";

class HeroAcademcy {
    
    @Inject
    heroService = HeroService; // Class

    @Inject
    HeroService = null;

    @Inject.optional
    godService = null;

    @Inject.named("HeroService")
    peopleService = null;
}

const heroAcademy = new HeroAcademcy();

console.log(heroAcademy.heroService.getHeroes()); // ["Saitama"];
console.log(heroAcademy.HeroService.getHeroes()); // ["Saitama"];
console.log(heroAcademy.godService); // null;
console.log(heroAcademy.peopleService.getHeroes()); // ["Saitama"];

Advanced

Decorators are exported both capitalized and lower-case for convenience.

Extend your decorators with chainable options, chaining the same option twice will use the latter option.

@Provides

Class decorator that declares a Class as Provider, creating new instances upon every injection.

  • lazy - Instantiate instance lazily.
    • Default: false
  • named(name) - Register dependency under name.
    • Default: Class

@Singleton

Class decorator that declares a Class as Singleton, creating a single instance for every injection.

  • lazy - Instantiate instance lazily.
    • Default: false
  • named(name) - Registers dependency under name.
    • Default: Class

@Inject

Class or property injection decorator that injects on constructor parameters, or ClassType or PropertyKey respectively.

  • computed - Computed property.
    • Default: false.
  • lazy - Computed property until invoked once, then becomes a static value.
    • Default: false.
  • optional - Injects undefined if not found.
    • Default: false
  • named(name) - Injects dependency under name.
    • Default: Class

Note: Calling a constructor with provided values means Dagger won't override those values (unless undefined). This is by design.

@Named(name)

Constructor parameter decorator used in conjunction with @Inject.

  • optional - Injects undefined if not found.

License

Dagger is available under the MIT license. See LICENSE for details.