assembler.js
A general purpose and zero-dependency Dependency Injection library for node and browser.

assembler.js
is inspired by both DIOD and Nestjs.
assembler.js
name is a tribute to Gilles Deleuze and Felix Guattari concept of Agencement (in french) that can be translated into Assemblage.
Install
yarn add assemblerjs
npm install assemblerjs
Usage
The main block of assembler.js
is the Assemblage. It is created by decorating classes with the @Assemblage
decorator. To keep everything type-safe, classes may implement AbstractAssemblage
abstract class or define their own abstract class that extends it.
These abstract classes are used as identifiers to inject dependencies.
Order of execution
Dependencies are registered and built recursively from the entry assemblage resolved by Assembler.build
.
onRegister
Static hook called when registering the assemblage.
Other dependencies may or may not have been registered at this point, and dependency tree is not built yet.
constructor
Build the instance and requires an instance of each dependency passed to the constructor.
If the dependency is not a singleton a new instance is returned, meaning the same dependency required in another assemblage will be another object, as when using the require
method of the AssemblerContext
passed to hooks or injected by the @Context
decorator.
onInit
Called on every dependency when the dependency tree is ready.
Except for the entry assemblage (i.e. the one built on bootstrap by Assembler.build
) the hook is called according to the latter.
The entry point assemblage is called last.
onDispose
Called when disposing the assembler via the dispose
method injected by the @Dispose
decorator.
This will be called like the onInit
method, walking through the dependency tree, except for the entry point assemblage, called last.
Events
assembler.js
provides an EventManager
that can be subclassed by any assemblage.
Because all events are forwarded by AssemblerContext
the EventManager
is quite strict on which events can be broadcasted and they must be registered explicitly using the events
property of the AssemblageDefinition
. To avoid collision between events channels, user is strongly encouraged to create strong channels names, e.g.: com.domain.app.assemblage-name:init
.
const prefix = 'com.domain.app.emitter-assemblage';
export enum EmitterAssemblageEvents {
Init = `${prefix}:init`,
}
@Assemblage({
events: Object.values(EmitterAssemblageEvents),
})
export class EmitterAssemblage
extends EventManager
implements AbstractEventAssemblage
{
constructor() {
super();
}
public async onInit(): Promise<void> {
this.emit(EmitterAssemblageEvents.Init, true);
}
}
@Assemblage()
export class SubcriberAssemblage implements AbstractAssemblage {
constructor(@Context() private context: AssemblerContext) {
context.on(EmitterAssemblageEvents.Init, (value: boolean) => {
console.log(value);
});
context.on('*', (value: boolean) => {
console.log(value);
});
}
}
Assembler.build(SubcriberAssemblage);