awilix-manager

Wrapper over awilix to support more complex use-cases
Getting started
First install the package:
npm i awilix-manager
Next, set up your DI configuration:
import { AwilixManager } from 'awilix-manager'
import { asClass, createContainer } from 'awilix'
class AsyncClass {
async init() {
}
async dispose() {
}
}
const diContainer = createContainer({
injectionMode: 'PROXY',
})
diContainer.register(
'dependency1',
asClass(AsyncClass, {
lifetime: 'SINGLETON',
asyncInitPriority: 10,
asyncDisposePriority: 10,
asyncInit: 'init',
asyncDispose: 'dispose',
eagerInject: true,
}),
)
const awilixManager = new AwilixManager({
diContainer,
asyncInit: true,
asyncDispose: true,
strictBooleanEnforced: true,
})
await awilixManager.executeInit()
await awilixManager.executeDispose()
Disabling eager injection conditionally
In some cases you may want to prevent eager injection and async disposal of some of your dependencies - e. g. when you want to disable all of your background jobs or message consumers in some of your integration tests.
You can use enabled
resolver parameter for that:
import { AwilixManager } from 'awilix-manager'
import { asClass, createContainer } from 'awilix'
class QueueConsumerClass {
async consume() {
}
async destroy() {
}
}
const diContainer = createContainer({
injectionMode: 'PROXY',
})
const isAMQPEnabled = false
diContainer.register(
'dependency1',
asClass(QueueConsumerClass, {
lifetime: 'SINGLETON',
asyncInitPriority: 10,
asyncDisposePriority: 10,
asyncInit: 'consume',
asyncDispose: 'destroy',
enabled: isAMQPEnabled,
}),
)
const awilixManager = new AwilixManager({
diContainer,
asyncInit: true,
asyncDispose: true,
strictBooleanEnforced: true,
})
await awilixManager.executeInit()
await awilixManager.executeDispose()
Note that passing undefined
or null
as a value for the enabled
parameter counts as a default, which is true
. That may lead to hard-to-debug errors, as it may be erroneously assumed that passing falsy value should equal to passing false
. In order to prevent this, it is recommended to set strictBooleanEnforced
flag to true
, which would throw an error if a non-boolean value is explicitly set to the enabled
field. In future semver major release this will become a default behaviour.
Fetching dependencies based on tags
In some cases you may want to get dependencies based on a supplied list of tags.
You can use tags
parameter in conjunction with the getWithTags
method for that:
import { AwilixManager } from 'awilix-manager'
import { asClass, createContainer } from 'awilix'
const diContainer = createContainer({
injectionMode: 'PROXY',
})
class QueueConsumerHighPriorityClass {
}
class QueueConsumerLowPriorityClass {
}
diContainer.register(
'dependency1',
asClass(QueueConsumerHighPriorityClass, {
lifetime: 'SINGLETON',
asyncInit: true,
tags: ['queue', 'high-priority'],
}),
)
diContainer.register(
'dependency2',
asClass(QueueConsumerLowPriorityClass, {
lifetime: 'SINGLETON',
asyncInit: true,
tags: ['queue', 'low-priority'],
}),
)
const awilixManager = new AwilixManager({
diContainer,
asyncInit: true,
asyncDispose: true,
})
const result1 = awilixManager.getWithTags(['queue'])
const result2 = awilixManager.getWithTags(['queue', 'low-priority'])
Fetching dependencies based on a predicate
In some cases you may want to get dependencies based on whether they satisfy some condition.
You can use getByPredicate
method for that:
import { AwilixManager } from 'awilix-manager'
import { asClass, createContainer } from 'awilix'
const diContainer = createContainer({
injectionMode: 'PROXY',
})
class QueueConsumerHighPriorityClass {
}
class QueueConsumerLowPriorityClass {
}
diContainer.register(
'dependency1',
asClass(QueueConsumerHighPriorityClass, {
lifetime: 'SINGLETON',
asyncInit: true,
}),
)
diContainer.register(
'dependency2',
asClass(QueueConsumerLowPriorityClass, {
lifetime: 'SINGLETON',
asyncInit: true,
}),
)
const awilixManager = new AwilixManager({
diContainer,
asyncInit: true,
asyncDispose: true,
})
const result1 = awilixManager.getByPredicate((entry) => entry instanceof QueueConsumerHighPriorityClass)
const result2 = awilixManager.getByPredicate((entry) => entry instanceof QueueConsumerLowPriorityClass))
Note that this will resolve all non-disabled dependencies within the container, even the ones without eager injection enabled.
Mocking dependencies
Sometimes you may want to intentionally inject objects that do not fully conform to the type definition of an original class. For that you can use asMockClass
, asMockFunction
or asMockValue
resolvers:
type DiContainerType = {
realClass: RealClass
realClass2: RealClass
}
const diConfiguration: NameAndRegistrationPair<DiContainerType> = {
realClass: asClass(RealClass),
realClass2: asMockClass(FakeClass),
}
const diContainer = createContainer<DiContainerType>({
injectionMode: 'PROXY',
})
for (const [dependencyKey, dependencyValue] of Object.entries(diConfiguration)) {
diContainer.register(dependencyKey, dependencyValue as Resolver<unknown>)
}
const { realClass, realClass2 } = diContainer.cradle
expect(realClass).toBeInstanceOf(RealClass)
expect(realClass2).toBeInstanceOf(FakeClass)