dependabot[bot] on npm_and_yarn
chore(deps): bump y18n from 4.0… (compare)
$> npx tsc
node_modules/awilix/lib/list-modules.d.ts:1:23 - error TS7016: Could not find a
declaration file for module 'glob'. '/[...]/api/node_modules/awilix/node_modules/glob/glob.js' implicitly has an 'any' type.
Try `npm install @types/glob` if it exists or add a new declaration (.d.ts) f
ile containing `declare module 'glob';`
1 import * as glob from 'glob';
container.loadModules(
[
[
'modules/**/service.ts',
{
register: asClass,
lifetime: Lifetime.SCOPED
}
],
[
'modules/**/repository.ts',
{
register: asClass,
lifetime: Lifetime.SINGLETON
}
]
],
{
cwd: __dirname
}
);
Hi there! I've been using Awilix for almost 2 years now and really enjoying it.
I'm currently trying to namespace or group my deps. I stumbled upon this snippet on the conversation above:
function groupRegistrationsBy(predicate: (registrationName: string) => boolean): Resolver<any> {
return {
resolve: c =>
_(c.registrations)
.keys()
.filter(predicate)
.reduce(
(registrationsGroup, registrationName) => ({
...registrationsGroup,
[registrationName]: c.resolve(registrationName)
}),
{}
)
};
}
container.register({
repositories: groupRegistrationsBy(reg => _.endsWith(reg, 'Repository'),
routers: groupRegistrationsBy(reg => _.endsWith(reg, 'Router')
})
This seems to be a reasonable approach for what I want to do but here you first register everything and then group things using these registrations. Is it possible to do it one shot: load modules and group it at the time ?
loadModules
yourself and group + register the result.loadedModules
app
module I need to access the domain
, but if in the domain
I need domain
too, even though I won't use the same module in the end, it throws because of cyclic dependencies
I managed to do it like that:
container.loadModules(['+(app|domain|infra)/**/!(*.spec).+(js|ts)'], {
formatName: (name, descriptor) => {
const splat = descriptor.path.split('/');
const namespace = splat[splat.length - 2];
return namespace + '.' + name;
},
resolverOptions: {lifetime: Lifetime.SINGLETON},
cwd: __dirname
});
It makes the job, using deps in modules is a bit verbose though:
import {ITestDomain} from 'domain/testDomain';
export interface ITestApp {
myFunc(): string;
}
interface IDeps {
['domain.testDomain']: ITestDomain;
}
export default function({['domain.testDomain']: testDomain}: IDeps) {
return {
myFunc: () => testDomain.someFunc()
};
}
has anyone worked with typescript and awilix? I'm using awilix for DI but i'm having an issue with some eslint errors saying that:
Property 'container' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs>'
import Status from "http-status-codes";
import { ErrorRequestHandler, NextFunction, Request, Response } from "express";
const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
const { logger } = req.container.cradle;
};
What do you think of this approach
import { createContainer, Lifetime } from 'awilix'
interface IDeps {
[key: string]: any
}
function createAppContainer() {
const container = createContainer<IDeps>()
container.loadModules([`${__dirname}/**/providers/**/!(*.spec|*.d|*.test).{js,ts}`], {
resolverOptions: {
lifetime: Lifetime.SINGLETON,
},
})
return container
}
export { createAppContainer, IDeps }
configProvider.ts
import { RESOLVER } from 'awilix'
import createConfig from '~/config'
type IConfig = ReturnType<typeof createConfig>
declare module '~/container' {
interface IDeps {
config: IConfig
}
}
function configProvider(): IConfig {
if (process.env.NODE_ENV !== 'production') {
process.env.USE_DOTENV = 'true'
}
return createConfig()
}
configProvider[RESOLVER] = {
name: 'config',
}
export default configProvider
redisProvider.ts
import Redis from 'ioredis'
import { RESOLVER } from 'awilix'
import { IDeps } from '~/container'
declare module '~/container' {
interface IDeps {
redis: ReturnType<typeof redisProvider>
}
}
function redisProvider(deps: IDeps) {
const { config } = deps
const redisUrl = config.get('redis_url')
const globalClient = new Redis(redisUrl)
const clients: Record<string, Redis.Redis> = {}
function getClient(name: string) {
if (!name) {
return globalClient
}
if (!clients[name]) {
clients[name] = globalClient.duplicate()
}
return clients[name]
}
return {
getClient,
}
}
redisProvider[RESOLVER] = {
name: 'redis',
}
export default redisProvider
Is there any best practise for handling async services? I'm trying to get awilix working properly with puppeteer and mysql2/promise. Both of them have an async launch/connect function. I've read some stuff on Github about doing it this way:
const browser = await puppeteer.launch({...})
container.register({
browser: asFunction(() => browser)
.singleton()
.disposer(browser => browser.close())
})
The problem I have with this solution is that the disposer is not called unless the service was resolved atleast once.
container.register({ awilix.asFunction(() => connection.getCustomRepository(UserRepository) });
however i'd like to do this dynamically and without having to each repository's class name, ie. using loadModules. looking for the equivalent of something like this:import { getCustomRepository } from 'typeorm';
container.loadModules(['src/repositories/**/*'], {
register: (modules) =>
modules.map((m) => asClass(getCustomRepository(m))
),
resolverOptions: {
injectionMode: InjectionMode.PROXY,
lifetime: Lifetime.SINGLETON,
},
});