Getting started
Installation
Deno
deno add @arthur-fontaine/diabolo
You can change your import map (in deno.json
) to allow for imports like
import * as DI from 'diabolo'
.
{
"imports": {
- "@arthur-fontaine/diabolo": "jsr:@arthur-fontaine/diabolo"
+ "diabolo": "jsr:@arthur-fontaine/diabolo"
}
}
Other environments
echo "@jsr:registry=https://npm.jsr.io" >> .npmrc
pnpm i diabolo@npm:@jsr/arthur-fontaine__diabolo
See why we use JSR instead of NPM here: https://jsr.io/docs/why.
What is dependency injection?
Dependency injection is a technique used to create loosely coupled software components, enhancing the modularity, to make the software easier to maintain and test.
A common use case for dependency injection is to create an API service. In your application, you can implement the API service using a real network request, and in your tests, you can implement the API service using mock data.
That’s where dependency injection comes in. However, using dependency injection in the JavaScript ecosystem is not a common practice, despite its benefits.
What is Diabolo?
Diabolo is a library that provides a simple and type-safe way to implement dependency injection in JavaScript. It is inspired by the Effect library.
Example
import * as DI from 'diabolo'
interface AdderService extends DI.Service<'Adder', {
add: (a: number, b: number) => number
}> { }
const adderService = DI.createService<AdderService>('Adder')
const adderServiceImpl = DI.lazyCreateServiceImpl<AdderService>(() => ({
add: (a: number, b: number) => a + b,
}))
const mainFunction = DI.createFunction(function* () {
const adder = yield * DI.requireService(adderService)
return adder.add(1, 2)
})
const result = DI.provide(mainFunction, {
Adder: adderServiceImpl,
})()
// result === 3
Comparison with other libraries
Effect
Effect is a library with a large (too large?) scope. At the time I am writing this, the “Unpacked size” of Effect on NPM is 16.3 MB. In comparison, the “Unpacked size” of Diabolo is only a few dozen KB.
Among other things, Effect provides a way to manage dependency injection.
To achieve dependency injection in Effect, you need to use at least 3 modules:
Effect
, Context
, and Layer
. Effect
has 305 exported members, Context
has 14 exported members, and Layer
has 79 exported members. That can make
it difficult to understand how to use the library.
Also, as mentioned above, the purpose of dependency injection is decoupling. However, Effect describes itself as “the missing standard library for TypeScript”. Depending on how you use Effect, it may be contrary to the principle of decoupling.
Diabolo, on its side, is a library with a very small scope. It only provides a way to manage dependency injection. Its exported members can be counted on the fingers of one hand. It is very easy to understand how to use the library.
InversifyJS and TSyringe
InversifyJS and TSyringe are two popular dependency injection libraries for TypeScript.
As just mentioned, they are dependency injection libraries for TypeScript, and only for TypeScript. They cannot be used with vanilla JavaScript.
They also rely on TypeScript experimentalDecorators
, which are not
compatible with the TC39 decorators proposal, as
TypeScript decorators are based on an old version of the proposal.
Moreover, you will likely need to install reflect-metadata
to use
decorators.
If you use Babel in your project, you will also need to install
babel-plugin-transform-typescript-metadata
.
On the other hand, Diabolo is very simple to use. It does not require any other dependencies. It is cross-platform because it relies on generators, which are available in all JavaScript environments since 2016.
Motivation
I am a big fan of the Effect library. However, it is very complex. Even the most experienced developers can have a hard time understanding the whole library. The concept I found most interesting in Effect is the dependency injection part. So I decided to create a simpler library (strongly inspired by Effect) that only focuses on dependency injection.
This way, my friends can use (and learn) dependency injection in our school projects.