#lazy loading 3rd party module fails

102 messages ยท Page 1 of 1 (latest)

sick tundra
#

NestJS fails to lazily inject third-party dependencies. I've tested with both nest-mongodb and @golevelup/nestjs-rabbitmq, here is a reproduction with the former: https://github.com/timm-stelzer-e-farm/nestjs-dependency-injections-issue. Running start:lazy fails with:

UnknownDependenciesException [Error]: Nest can't resolve dependencies of the DatabaseService (?). Please make sure that the argument fooDb at index [0] is available in the DatabaseModule context.

Potential solutions:
- If fooDb is a provider, is it part of the current DatabaseModule?
- If fooDb is exported from a separate @Module, is that module imported within DatabaseModule?
  @Module({
    imports: [ /* the Module containing fooDb */ ]
  })

    at Injector.lookupComponentInParentModules (/<path>/node_modules/@nestjs/core/injector/injector.js:241:19)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)

Would expect both start:eager and start:lazy to work as expected.

I created an issue at https://github.com/nestjs/nest/issues/10458, which was closed, which I guess means its on my end? Would appreciate some pointers.

GitHub

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications on top of TypeScript & JavaScript (ES6, ES7, ES8) ๐Ÿš€ - Issues ยท nestjs/nest

sick tundra
#

Bump, this would genuinely improve our code, we currently have to statically define root modules for half-a-dozen use-cases.

soft hornet
tulip drum
#

Could you try the workaround mentioned in the issue above?

sick tundra
#

I'm not sure how I would use that workaround in my case.

#

The dependency isn't defined globally, that's the point. Is should only be created on-demand.

#

It's specifically injected into the lazy module.

sick tundra
#

I updated the repository to better reflect the issue. That should show that's its not the same issue as the linked one ๐Ÿค”

tulip drum
#

What if you call await context.init() before get?

sick tundra
#

Same issue.

soft hornet
sick tundra
#

oh, by default, ugh

#

i see

#

i'm still not sure how i can implement that workaround in my case, though

soft hornet
#

this.dbService = this.modRef.get(getDbToken(dbName)) would probably do it in the onModuleInit

sick tundra
#

let me try

#

doesn't seem to work

#
file:///<PATH>/nestjs-dependency-injections-issue/lazy.ts:22
        await this.test.insertOne({qux: 42});
                        ^
TypeError: Cannot read properties of undefined (reading 'insertOne')
    at DatabaseService.insert (file://<PATH>nestjs-dependency-injections-issue/lazy.ts:22:25)
    at main (file://<PATH>/nestjs-dependency-injections-issue/lazy.ts:54:14)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
soft hornet
#

Okay, now I'm not familiar with mongo on pretty much any level. How should the db.collection('test') get created?

sick tundra
#

that's implicitly created on access

#

thats a mongodb driver feature

#

onModuleInit is never called, do i have to do that manually?

#

same result

soft hornet
#

You know, it's funny. The docs say that lifecycle methods actually don't work on lazy services and modules, so the workaround wouldn't be valid automatically, you'd have to call dbService.onModuleInit() manually

#

And yep, when I set the correct connectionName in the getDbToken() and call db.onModuleInit() manually everything works as expected

sick tundra
#

Interesting, thats what i did and it didnt work

#

Grocery shopping right now, will try later

soft hornet
#
  onModuleInit() {
    this.db = this.moduleRef.get(getDbToken(connectionName), { strict: false });
    this.test = this.db.collection("test");
  }
sick tundra
#

oh, i gotta pass connectionName, right

#

yeah, that seems to work

#

brilliant

#

i'll try to implement this for our work code base, but thanks so much already @soft hornet!

tulip drum
#

jay is the best!
@sick tundra you can close this post now if you want to ๐Ÿ™‚

sick tundra
#

Haven't tested with the "real-world" code yet, will close it if its working ๐Ÿ™‚

sick tundra
#

works with mongodb โค๏ธ

#

now i'm trying to figure out how to solve the same issue with @golevelup/nestjs-rabbitmq

#

yeah, doesn't work, but different issue ๐Ÿ˜

#

Nest can't resolve dependencies of the DiscoveryService (?, MetadataScanner)

#

That one isn't Global though

soft hornet
#

Is that @golevelup's DiscoveryService?

sick tundra
#
import { DiscoveryModule, DiscoveryService } from '@golevelup/nestjs-discovery';
#

yup

#

do i need to inject that as well?

#

tbh, i'm not sure how to get the module token for @golevelup/nestjs-rabbitmq

soft hornet
#

Hmm, probably not? The thing it's trying to inject is ModulesContainer which is kind of an internal provider. What's the full error you're getting?

soft hornet
#

And is this specifically for a lazy service?

sick tundra
#

yes, lazy

soft hornet
#

Ah, I think that's an issue here then

sick tundra
#
UnknownDependenciesException [Error]: Nest can't resolve dependencies of the DiscoveryService (?, MetadataScanner). Please make sure that the argument ModulesContainer at index [0] is available in the DiscoveryModule context.

Potential solutions:
- If ModulesContainer is a provider, is it part of the current DiscoveryModule?
- If ModulesContainer is exported from a separate @Module, is that module imported within DiscoveryModule?
  @Module({
    imports: [ /* the Module containing ModulesContainer */ ]
  })

    at Injector.lookupComponentInParentModules (</node_modules/@nestjs/core/injector/injector.js:241:19)
soft hornet
#

I believe some of the internal modules like ModulesContainer are technically global. Let me see if I can find that, cause ModuleRef isn't ๐Ÿค”

sick tundra
#

right, soo, i have to inject that? ๐Ÿ˜„

soft hornet
#

No, I think until the bug around this is fixed you've hit a wall

sick tundra
#

damn

#

no workaround?

soft hornet
#

no workaround?
Not that I can thnk of at the moment

sick tundra
#

then thanks so far, i'll close this and subscribe to that pr ๐Ÿ˜„

chilly bough
#

It would be super nice if we could somehow have modules which can be pulled in on any version given that they're compatible. It's annoying that things break all the time and require people to update (I do understand why btw, just wondering if there is a work around ๐Ÿ˜› )

soft hornet
soft hornet
#

As for contact info, nope. You can check if he added it to his repo though

chilly bough
chilly bough
soft hornet
chilly bough
#
    "peerDependencies": {
        "@nestjs/common": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0",
        "@nestjs/core": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0",
        "mongodb": "^6.0.0",
        "reflect-metadata": "^0.1.13",
        "rxjs": "^6.0.0 || ^7.0.0"
    },
#

Can you think of any reason why it shouldn't just be

#
    "peerDependencies": {
        "@nestjs/common": ">=6.0.0",
        "@nestjs/core": ">=6.0.0",
        "mongodb": "^6.0.0",
        "reflect-metadata": "^0.1.13",
        "rxjs": "^6.0.0 || ^7.0.0"
    },
#

It's unlikely the module system is going to change in NestJS future versions right? Shouldn't this just be the recommended approach?

soft hornet
chilly bough
#

Yes, I remember, but ideally... you'd just install a version of this package supported for that version of nest

#

wouldn't it make more sense that way?

#

Because it's annoying how a majority of packages just don't break with new versions of nestjs, but the maintainers just don't bother updating them even with PRs

#

so you have to clone the repo

#

republish it to npm

#

and litter npm with the newer version thats actually maintained by someone which the maintenance most of the time is just package versions and minor bug fixes

soft hornet
chilly bough
#

I agree, but like I said, some packages don't break between nestjs versions, so surely there is a way around this?

soft hornet
#

The whole point is peer deps is to get the package manager "hey, this is necessary, but it'll be installed by another package/command, so don't install it with this package"

chilly bough
#

yeah, hmmm. I'll give it a go now, see what happens

#

im pretty sure it failed last time

#

but i'll check

soft hornet
#

Knowing what specifically is failing will improve this process tremendously

chilly bough
#

meh, ill give it a shot now, probably nothing burger and I'm making it up

#

we'll see ๐Ÿ˜›

#
PS D:\projects\hrefsmedia\craftsman> npm i --save nest-mongodb
npm ERR! code ERESOLVE                                                                     
npm ERR! ERESOLVE unable to resolve dependency tree                                        
npm ERR!                                                                                   
npm ERR! While resolving: craftsman@0.0.1                                                  
npm ERR! Found: @nestjs/common@10.2.10                                                     
npm ERR! node_modules/@nestjs/common                                                       
npm ERR!   @nestjs/common@"^10.2.8" from the root project                                  
npm ERR!                                                                                   
npm ERR! Could not resolve dependency:                                                     
npm ERR! peer @nestjs/common@"^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" from nest-mongodb@6.4.0
npm ERR! node_modules/nest-mongodb                                                         
npm ERR!   nest-mongodb@"*" from the root project                                          
npm ERR!                                                                                   
npm ERR! Fix the upstream dependency conflict, or retry                                    
npm ERR! this command with --force or --legacy-peer-deps                                   
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.            
npm ERR!                                                                                   
npm ERR!                                                                                   
npm ERR! For a full report see:
npm ERR! C:\Users\Kieron\AppData\Local\npm-cache\_logs\2023-11-27T23_30_26_113Z-eresolve-report.txt

npm ERR! A complete log of this run can be found in: C:\Users\Kieron\AppData\Local\npm-cache\_logs\2023-11-27T23_30_26_113Z-debug-0.log
soft hornet
#

That's specifically an npm issue, because of how it tries to handle peer deps and not at all related but NestJS (at least at runtime). You can use --legacy-peer-deps to get around it and bother the package maintainers to fix their package

chilly bough
#

Yeah I have, he accepted the PR to update versions and said "I will make a release soon"

soft hornet
#

Yarn and pnpm also behave differently here, just fyi

chilly bough
#

idk why you just wouldn't do it all in one go

chilly bough
soft hornet