Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error using nestjs-cls in an external module #51

Closed
alessandrosangalli opened this issue Jan 20, 2023 · 6 comments
Closed

Error using nestjs-cls in an external module #51

alessandrosangalli opened this issue Jan 20, 2023 · 6 comments
Labels
investigation Why is this happening? question Further information is requested solved The question was answered or the problem was solved

Comments

@alessandrosangalli
Copy link

I have a external module (in a private repository) using nestjs-cls

MyModuleUsingNestjsCls
imports
ClsModule.forRoot({
global: true,
middleware: { mount: true },
})
provide: MyServiceUsingClsService
exports: MyServiceUsingClsService

This module has a provider that uses ClsService:
class MyService constructor(private readonly clsService: ClsService) {}

This app works fine when i start this module, the cls service also works.

If i import MyModuleUsingNestjsCls in another nestjs app like this:
MyAnotherAppModule imports MyModuleUsingNestjsCls (from an repository like import { MyModuleUsingNestjsCls } 'my-private-lib')

I have the following error: Nest can't resolve dependencies of the ClsModule (?, ModuleRef). Please make sure that the argument HttpAdapterHost at index [0] is available in the ClsModule context.

Any idea why this happens?

@Papooch
Copy link
Owner

Papooch commented Jan 22, 2023

First thing that comes to mind, which is pretty common, is that the versions of @nestjs/* dependencies of the published library do not match the ones in the app, therefore looking for a different HttpAdapterHost. Make sure that all @nestjs/* dependencies in your library are peerDependencies with somewhat loose ranges, so it stays compatible when your app's dependencies update.

If you want me to investigate further, I'll need some reproducible example that I could look at.

@Papooch Papooch added question Further information is requested investigation Why is this happening? labels Jan 22, 2023
@alessandrosangalli
Copy link
Author

alessandrosangalli commented Jan 23, 2023

I create two repositories to reproduce.

A lib using nestjs-cls: https://github.com/alessandrosangalli/lib-with-cls
And an app using the 'lib-with-cls': https://github.com/alessandrosangalli/app-using-lib

You can clone both in the same folder like /src/lib-with-cls and /src/app-using-lib because the app is pointing to local lib in package json "lib-with-cls": "file:../lib-with-cls".

To reproduce:
cd lib-with-cls -> npm i -> npm run build
cd app-using-lib -> npm i -> npm run start dev

You should see Error: Nest can't resolve dependencies of the ClsModule (?, ModuleRef). Please make sure that the argument HttpAdapterHost at index [0] is available in the ClsModule context.

Both repositories are created from the same NestJS version (9.1.4). This just happens when nestjs-cls is in a lib, when i use directly in my app works fine.

@Papooch
Copy link
Owner

Papooch commented Jan 24, 2023

I just looked at the code and indeed, you have hard dependencies on @nestjs/* and other things in the library code. This will cause two versions of the libs being installed (especially using the file:.. protocol, because npm can't dedupe the dependencies in that case), which breaks the instanceof check that NestJS relies on.
All these should be peerDependencies:
image

Although I'm not entirely sure if you can use the file:.. protocol with NestJS projects at all..

@Papooch
Copy link
Owner

Papooch commented Jan 24, 2023

Yep, the issue is definitely with duplicate package install. Setting the dependencies to peerDependencies does not help in this case (but should help for a published package).
Manually moving the built files without node_modules inside the app-using-lib and linking it there causes the app to start successfully:
image
The underlying reason is that using the link:.. protocol causes the library code to load dependencies from its own node_modules, so even when the version of @nestjs/common is the same, the loaded code is different, which in turn breaks the dependency injection. When you publish the package and install it "normally", the problem should be gone.

This is a known problem of NPM (you can read more about it here npm/npm#7742, maybe it will give you some ideas about how to solve it). The general advice is to avoid using the link: protocol. There's a suggested workaround mentioned in this SO answer https://stackoverflow.com/a/74133390/4429729. Alternatively, you can use yarn or pnpm in the workspaces (monorepo) mode to leverage its dedupe mechanism (there's some suggestions at the bottom of the NestJS FAQ page as well)

@Papooch
Copy link
Owner

Papooch commented Jan 24, 2023

I just confirmed that the pack method mentioned by the SO answer does work.

  1. Run npm pack in the library folder
  2. Link the generated .tgz file in the app's package.json

image

The application then bootstraps successfully, using only the app's own node_modules:
image

@Papooch Papooch closed this as completed Jan 24, 2023
@alessandrosangalli
Copy link
Author

In real app my lib is published, so peer dependencies solved the problem. Thank you!

@Papooch Papooch added the solved The question was answered or the problem was solved label Jul 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
investigation Why is this happening? question Further information is requested solved The question was answered or the problem was solved
Projects
None yet
Development

No branches or pull requests

2 participants