Dagger
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
undefinedif 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
undefinedif not found.
License
Dagger is available under the MIT license. See LICENSE for details.