Error using nestjs-cls in an external module
alessandrosangalli opened this issue · comments
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?
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.
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.
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
:
Although I'm not entirely sure if you can use the file:..
protocol with NestJS projects at all..
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:
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)
In real app my lib is published, so peer dependencies solved the problem. Thank you!