Skip to content

EntityManager injection broken >5.1.2 with custom factory using PinoLogger and built via ncc #128

@AndKiel

Description

@AndKiel

Describe the bug
EntityManager (MongoEntityManager) dependency injection cannot be resolved when using @mikro-orm/nestjs >5.1.2 with .forRootAsync and PinoLogger. It works fine without injecting the logger into custom useFactory. Happens only when executing built code.

Stack trace

$ node ./dist/index.js
[Nest] 28664  - 07/18/2023, 11:02:59 AM     LOG [NestFactory] Starting Nest application...
[Nest] 28664  - 07/18/2023, 11:02:59 AM     LOG [InstanceLoader] AppModule dependencies initialized +97ms
[Nest] 28664  - 07/18/2023, 11:02:59 AM     LOG [InstanceLoader] MikroOrmModule dependencies initialized +0ms
[Nest] 28664  - 07/18/2023, 11:02:59 AM   ERROR [ExceptionHandler] Nest can't resolve dependencies of the MongoService (?). Please make sure that the argument MongoEntityManager at index [0] is available in the MongoModule context.

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

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

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

    at Injector.lookupComponentInParentModules (/Users/akieltyka/RubymineProjects/DeepCrawl/mikro-orm-nestjs-bug/webpack:/mikro-orm-nestjs-bug/node_modules/@nestjs/core/injector/injector.js:254:1)
    at Injector.resolveComponentInstance (/Users/akieltyka/RubymineProjects/DeepCrawl/mikro-orm-nestjs-bug/webpack:/mikro-orm-nestjs-bug/node_modules/@nestjs/core/injector/injector.js:207:1)
    at resolveParam (/Users/akieltyka/RubymineProjects/DeepCrawl/mikro-orm-nestjs-bug/webpack:/mikro-orm-nestjs-bug/node_modules/@nestjs/core/injector/injector.js:128:1)
    at async Promise.all (index 0)
    at Injector.resolveConstructorParams (/Users/akieltyka/RubymineProjects/DeepCrawl/mikro-orm-nestjs-bug/webpack:/mikro-orm-nestjs-bug/node_modules/@nestjs/core/injector/injector.js:143:1)
    at Injector.loadInstance (/Users/akieltyka/RubymineProjects/DeepCrawl/mikro-orm-nestjs-bug/webpack:/mikro-orm-nestjs-bug/node_modules/@nestjs/core/injector/injector.js:70:1)
    at Injector.loadProvider (/Users/akieltyka/RubymineProjects/DeepCrawl/mikro-orm-nestjs-bug/webpack:/mikro-orm-nestjs-bug/node_modules/@nestjs/core/injector/injector.js:97:1)
    at /Users/akieltyka/RubymineProjects/DeepCrawl/mikro-orm-nestjs-bug/webpack:/mikro-orm-nestjs-bug/node_modules/@nestjs/core/injector/instance-loader.js:56:1
    at async Promise.all (index 3)
    at InstanceLoader.createInstancesOfProviders (/Users/akieltyka/RubymineProjects/DeepCrawl/mikro-orm-nestjs-bug/webpack:/mikro-orm-nestjs-bug/node_modules/@nestjs/core/injector/instance-loader.js:55:1)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

To Reproduce
package.json

{
  "name": "mikro-orm-nestjs-bug",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "compile": "tsc",
    "build": "ncc build --out dist --source-map ./reproduction.ts",
    "run:ts-node": "yarn ts-node ./reproduction.ts",
    "run:built": "node ./dist/index.js"
  },
  "resolutions": {
    "mongodb": "4.1.4"
  },
  "dependencies": {
    "@mikro-orm/core": "5.7.13",
    "@mikro-orm/mongodb": "5.7.13",
    "@mikro-orm/nestjs": "5.2.0",
    "@nestjs/common": "10.1.0",
    "@nestjs/config": "3.0.0",
    "@nestjs/core": "10.1.0",
    "nestjs-pino": "3.3.0",
    "pino-http": "8.3.3",
    "reflect-metadata": "0.1.13",
    "source-map-support": "0.5.21",
    "tslib": "2.6.0"
  },
  "devDependencies": {
    "@nestjs/cli": "10.1.4",
    "@nestjs/schematics": "10.0.1",
    "@nestjs/testing": "10.0.5",
    "@types/node": "18.16.19",
    "@vercel/ncc": "0.36.1",
    "ts-node": "10.9.1",
    "typescript": "5.1.6"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "target": "es2021",
    "lib": ["es2021"],
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "module": "commonjs",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

reproduction.ts

import "reflect-metadata";

import { BaseEntity, Entity, PrimaryKey, SerializedPrimaryKey } from "@mikro-orm/core";
import { EntityManager, ObjectId } from "@mikro-orm/mongodb";
import { MikroOrmModule } from "@mikro-orm/nestjs";
import { INestApplicationContext, Injectable, Module, Scope } from "@nestjs/common";
import { NestFactory } from "@nestjs/core";
import { LoggerModule, PinoLogger } from "nestjs-pino";

@Entity({ collection: "entities" })
export class MongoEntity extends BaseEntity<MongoEntity, "id"> {
  @PrimaryKey()
  public _id!: ObjectId;

  @SerializedPrimaryKey()
  public id!: string;
}


@Injectable({ scope: Scope.TRANSIENT })
export class MongoService {
  private entityManager: EntityManager;

  constructor(entityManager: EntityManager) {
    this.entityManager = entityManager.fork();
  }
}

@Module({ providers: [MongoService] })
export class MongoModule {}

@Module({
  imports: [
    LoggerModule.forRoot(),
    MikroOrmModule.forRootAsync({
      inject: [PinoLogger],
      useFactory: (logger: PinoLogger) => {
        logger.setContext("MikroOrm");

        return {
          type: "mongo",
          clientUrl: "mongodb://127.0.0.1:27017/dbName", // run a local dockerized MongoDB v3 instance
          dbName: "dbName",
          entities: [MongoEntity],
          debug: ["query"], // Log all queries
          logger: message => logger.info(message),
        };
      },
    }),
    MongoModule,
  ],
})
class AppModule {}

let applicationContext: INestApplicationContext;

if (require.main === module) {
  (async () => {
    applicationContext = await NestFactory.createApplicationContext(AppModule);
    applicationContext = await applicationContext.init();
    await applicationContext.resolve(MongoService);
    await applicationContext.close();
    process.exit(0)
  })().catch(async error => {
    await applicationContext?.close();
    throw error;
  });
}
yarn install
yarn build
yarn run:built

Expected behavior
I expect the EntityManager to get injected correctly and work as it was working before in version 5.1.2.

Additional context
The error happens only when running a built .js file. It does not occur when running .ts file via ts-node. The mongodb dependency is locked to version 4.1.4 because of an old MongoDB v3 instance that needs to be connected to.

Versions

Dependency Version
node 18.16.1
typescript 5.1.6
mikro-orm 5.7.13
mongodb 4.1.4

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions