NestJS共享数据库模块报UnknownDependenciesException错误求助
问题:NestJS共享数据库包依赖解析错误
我有多个使用同一数据库的NestJS应用,尝试将数据库实体、仓库迁移至独立的共享包(my-db-package)以实现复用,但已卡在此问题3天。运行消费应用时出现依赖解析错误,附上相关代码及完整报错信息,恳请协助解决。
共享包代码
// 注:原代码开头存在片段缺失,保留原样 config: DataSourceOptions; additionalEntities?: Function[]; } import { DynamicModule, Module } from '@nestjs/common'; import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm'; import { SharedDatabaseModuleOptions, FlexibleSharedDatabaseModuleOptions } from './database-module.interface'; import { Media } from '../entities/media.entity'; import { DataSourceOptions } from 'typeorm'; @Module({}) export class SharedDatabaseModule { static forRoot(opts: SharedDatabaseModuleOptions): DynamicModule { const entities = [Media, ...(opts.additionalEntities || [])]; const dsOptions: DataSourceOptions = { ...opts.config, entities, }; return { module: SharedDatabaseModule, imports: [ TypeOrmModule.forRoot(dsOptions), TypeOrmModule.forFeature(entities), ], exports: [TypeOrmModule], }; } }
消费应用代码
import { AppController } from './app.controller'; import { AppService } from './app.service'; import { EnvConfigModule } from './env-config/env-config.module'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { TypeOrmModule } from '@nestjs/typeorm'; import { SharedDatabaseModule } from 'my-db-package' @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true }), SharedDatabaseModule.forRoot({ config: { type: 'postgres', host: process.env.DB_HOST || 'localhost', port: parseInt(process.env.DB_PORT) || 5432, username: process.env.DB_USERNAME || 'postgres', password: process.env.DB_PASSWORD || 'password', database: process.env.DB_NAME || 'mydb', }, additionalEntities: [ ], }), ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
报错信息
ERROR [ExceptionHandler] UnknownDependenciesException [Error]: Nest can't resolve dependencies of the TypeOrmCoreModule (TypeOrmModuleOptions, ?). Please make sure that the argument ModuleRef at index [1] is available in the TypeOrmCoreModule context. Potential solutions: - Is TypeOrmCoreModule a valid NestJS module? - If ModuleRef is a provider, is it part of the current TypeOrmCoreModule? - If ModuleRef is exported from a separate @Module, is that module imported within TypeOrmCoreModule? @Module({ imports: [ /* the Module containing ModuleRef */ ] }) at Injector.lookupComponentInParentModules (/Users/codincops/Desktop/Projects/ubu/ubu-shared-db/node_modules/@nestjs/core/injector/injector.js:262:19) at async Injector.resolveComponentInstance (/Users/codincops/Desktop/Projects/ubu/ubu-shared-db/node_modules/@nestjs/core/injector/injector.js:215:33) at async resolveParam (/Users/codincops/Desktop/Projects/ubu/ubu-shared-db/node_modules/@nestjs/core/injector/injector.js:129:38) at async Promise.all (index 1) at async Injector.resolveConstructorParams (/Users/codincops/Desktop/Projects/ubu/ubu-shared-db/node_modules/@nestjs/core/injector/injector.js:144:27) at async Injector.loadInstance (/Users/codincops/Desktop/Projects/ubu/ubu-shared-db/node_modules/@nestjs/core/injector/injector.js:70:13) at async Injector.loadProvider (/Users/codincops/Desktop/Projects/ubu/ubu-shared-db/node_modules/@nestjs/core/injector/injector.js:98:9) at async /Users/codincops/Desktop/Projects/ubu/ubu-shared-db/node_modules/@nestjs/core/injector/instance-loader.js:56:13) at async Promise.all (index 0) at async InstanceLoader.createInstancesOfProviders (/Users/codincops/Desktop/Projects/ubu/ubu-shared-db/node_modules/@nestjs/core/injector/instance-loader.js:55:9) { type: 'TypeOrmCoreModule', context: { index: 1, dependencies: [ 'TypeOrmModuleOptions', [class ModuleRef extends AbstractInstanceResolver] ], name: [class ModuleRef extends AbstractInstanceResolver] }, metadata: { id: '793cfa692a3cf0f1a2f3c' }, moduleRef: { id: 'cfa692a3cf0f1a2f3ccf3' } }
解决方案
1. 修正共享包的依赖配置
确保@nestjs/common、@nestjs/typeorm、typeorm在共享包的package.json中配置为peerDependencies,而非dependencies,避免消费应用与共享包安装重复版本导致依赖冲突:
{ "peerDependencies": { "@nestjs/common": "^10.0.0", "@nestjs/typeorm": "^10.0.0", "typeorm": "^0.3.17", "reflect-metadata": "^0.1.13" } }
2. 重构SharedDatabaseModule实现
不要在forRoot中同时导入TypeOrmModule.forRoot和TypeOrmModule.forFeature,拆分逻辑并优化导出:
import { DynamicModule, Module, Provider } from '@nestjs/common'; import { TypeOrmModule, TypeOrmModuleAsyncOptions } from '@nestjs/typeorm'; import { SharedDatabaseModuleOptions, SharedDatabaseModuleAsyncOptions } from './database-module.interface'; import { Media } from '../entities/media.entity'; @Module({}) export class SharedDatabaseModule { // 同步初始化根数据库配置 static forRoot(opts: SharedDatabaseModuleOptions): DynamicModule { const entities = [Media, ...(opts.additionalEntities || [])]; return { module: SharedDatabaseModule, imports: [ TypeOrmModule.forRoot({ ...opts.config, entities, }), ], exports: [TypeOrmModule], }; } // 异步初始化(支持ConfigService注入) static forRootAsync(opts: SharedDatabaseModuleAsyncOptions): DynamicModule { return { module: SharedDatabaseModule, imports: [ TypeOrmModule.forRootAsync({ useFactory: async (...args: any[]) => { const config = await opts.useFactory(...args); const entities = [Media, ...(config.additionalEntities || [])]; return { ...config.config, entities, }; }, inject: opts.inject, }), ], exports: [TypeOrmModule], }; } // 提供实体注册方法,供消费应用扩展 static forFeature(entities: Function[]) { return TypeOrmModule.forFeature([...entities, Media]); } }
3. 更新共享包的接口定义
补充异步配置所需的接口:
import { DataSourceOptions } from 'typeorm'; import { FactoryProvider } from '@nestjs/common'; export interface SharedDatabaseModuleOptions { config: DataSourceOptions; additionalEntities?: Function[]; } export interface SharedDatabaseModuleAsyncOptions extends Pick<FactoryProvider, 'inject' | 'useFactory'> { useFactory: (...args: any[]) => Promise<SharedDatabaseModuleOptions> | SharedDatabaseModuleOptions; }
4. 优化消费应用的配置方式
改用异步配置注入ConfigService,避免直接使用process.env:
import { AppController } from './app.controller'; import { AppService } from './app.service'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { SharedDatabaseModule } from 'my-db-package' @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true }), SharedDatabaseModule.forRootAsync({ useFactory: (configService: ConfigService) => ({ config: { type: 'postgres', host: configService.get<string>('DB_HOST') || 'localhost', port: configService.get<number>('DB_PORT') || 5432, username: configService.get<string>('DB_USERNAME') || 'postgres', password: configService.get<string>('DB_PASSWORD') || 'password', database: configService.get<string>('DB_NAME') || 'mydb', }, additionalEntities: [], }), inject: [ConfigService], }), ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
5. 统一版本依赖
确保消费应用与共享包的@nestjs/core、@nestjs/typeorm、typeorm版本完全一致,版本不匹配是此类依赖注入错误的常见原因。
内容的提问来源于stack exchange,提问作者G M
相关产品推荐
相关产品推荐

