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

Problems Loading Nested DynamicModules With LazyModuleLoader #8031

Closed
felix-gohla opened this issue Sep 4, 2021 · 4 comments
Closed

Problems Loading Nested DynamicModules With LazyModuleLoader #8031

felix-gohla opened this issue Sep 4, 2021 · 4 comments
Labels
needs triage This issue has not been looked into

Comments

@felix-gohla
Copy link

felix-gohla commented Sep 4, 2021

Bug Report

tl;dr: Nested DynamicModules fail to inject dependencies / resolve providers correctly when using LazyModuleLoader.

Current behavior

Consider having 3 modules: ConfigModule, ModuleA and ModuleB.
ModuleA and ModuleB have static functions to create DynamicModules, where ModuleA depends on ModuleB and imports it.
When loading ModuleA from ConfigModule via a LazyModuleLoader, the dependencies of ModuleA (in that case the providers of ModuleB) seem not to be injected, resulting in the following message:

  throw new unknown_dependencies_exception_1.UnknownDependenciesException(wrapper.name, dependencyContext, moduleRef);
                  ^
Error: Nest can't resolve dependencies of the TOKENA (?). Please make sure that the argument SomeClassB at index [0] is available in the ModuleA context.

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

    at Injector.lookupComponentInParentModules (/Downloads/nestjs-nested-dynamic-module-reproduction/node_modules/@nestjs/core/injector/injector.js:193:19)
    at Injector.resolveComponentInstance (~/Downloads/nestjs-nested-dynamic-module-reproduction/node_modules/@nestjs/core/injector/injector.js:149:33)
    at resolveParam (~/Downloads/nestjs-nested-dynamic-module-reproduction/node_modules/@nestjs/core/injector/injector.js:103:38)
    at async Promise.all (index 0)
    at Injector.resolveConstructorParams (~/Downloads/nestjs-nested-dynamic-module-reproduction/node_modules/@nestjs/core/injector/injector.js:118:27)
    at Injector.loadInstance (~/Downloads/nestjs-nested-dynamic-module-reproduction/node_modules/@nestjs/core/injector/injector.js:47:9)
    at Injector.loadProvider (~/Downloads/nestjs-nested-dynamic-module-reproduction/node_modules/@nestjs/core/injector/injector.js:69:9)
    at async Promise.all (index 3)
    at InstanceLoader.createInstancesOfProviders (~/Downloads/nestjs-nested-dynamic-module-reproduction/node_modules/@nestjs/core/injector/instance-loader.js:44:9)
    at ~/Downloads/nestjs-nested-dynamic-module-reproduction/node_modules/@nestjs/core/injector/instance-loader.js:29:13

For clarification: My goal is to conditionally load different modules based on the instantiated ConfigService. So maybe this approach is not ideal, but the best one I could come up with.

Input Code

I created a small reproduction repository here: https://github.com/felix-gohla/nestjs-nested-dynamic-module-reproduction.
You can see that this does not happen when importing ModuleA directly in the AppModule and not via the config module.

Expected behavior

The exported providers of the dynamic module ModuleB should be injected successfully into ModuleA.

Possible Solution

It seems that in packages/core/injector/container.ts the function addModule is called multiple times for ModuleB when lazily loading the module, thus returning undefined in line 69 on subsequent calls.
In combination with the scanForModules and insertModule functions from packages/core/scanner.ts, which will be called from the LazyModuleLoader this seems to have the effect, that the returned moduleRef is undefined and the dependencies won't get resolved correctly due to line 129f.

Modifying packages/core/injector/container.ts:addModule to return the module, seems to fix the issue. But I'm not sure, what this could break:

diff --git a/packages/core/injector/container.ts b/packages/core/injector/container.ts
index e01336a..c1355bf 100644
--- a/packages/core/injector/container.ts
+++ b/packages/core/injector/container.ts
@@ -56,7 +56,7 @@ export class NestContainer {
   public async addModule(
     metatype: Type<any> | DynamicModule | Promise<DynamicModule>,
     scope: Type<any>[],
-  ): Promise<Module | undefined> {
+  ): Promise<Module> {
     // In DependenciesScanner#scanForModules we already check for undefined or invalid modules
     // We still need to catch the edge-case of `forwardRef(() => undefined)`
     if (!metatype) {
@@ -66,7 +66,7 @@ export class NestContainer {
       metatype,
     );
     if (this.modules.has(token)) {
-      return;
+      return this.modules.get(token);
     }
     const moduleRef = new Module(type, this);
     moduleRef.token = token;

Environment


Nest version: 8.0.6
(So this seems to be an issue in the latest Nest version, too.)
 
For Tooling issues:
- Node version: v16.6.2
- Platform:  Mac

Others:
yarn is used as package manager.
@felix-gohla felix-gohla added the needs triage This issue has not been looked into label Sep 4, 2021
@Gbuomprisco
Copy link

Can confirm, having the exact same issue

@lhr0909
Copy link

lhr0909 commented Sep 15, 2021

I am wondering if this is related: skunight/nestjs-redis#82

I am running into an exact same problem as the above issue, where I have a DynamicModule with a controller inside that is trying to inject ModuleRef. And I got an dependency error where the ModuleRef was not injected properly.

I can try to create a minimum reproduction here, but right now I am downgrading to NestJS v7 and it seems to be working.

@kamilmysliwiec
Copy link
Member

Have you tried adding await app.init() after this line https://github.com/felix-gohla/nestjs-nested-dynamic-module-reproduction/blob/main/src/main.ts#L6?

@kamilmysliwiec
Copy link
Member

Fixed in 8.0.9

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs triage This issue has not been looked into
Projects
None yet
Development

No branches or pull requests

4 participants