Skip to content

nest 模块

Nest 在启动的时候,会递归解析 Module 依赖

模块service使用其他模块内的service

模块导出 provider,另一个模块需要 imports 它才能用这些 provider。

GoodsModule exports 需要向外暴露的service

ts
// goods Module
import { Module } from '@nestjs/common';
import { GoodsService } from './goods.service';
import { GoodsController } from './goods.controller';

@Module({
  controllers: [GoodsController],
  providers: [GoodsService],
  exports: [GoodsService],
})
export class GoodsModule {}

UserModule 需要import GoodsModule, 然后才能在UserModule的PrivateInject

ts
// user Module
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { GoodsModule } from 'src/goods/goods.module';

@Module({
  imports: [GoodsModule], // import GoodsModule
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}

UserModule的Private中Inject

ts
import { GoodsService } from 'src/goods/goods.service';

@Injectable()
export class UserService {
  @Inject()
  private readonly goodService: GoodsService;

  findAll() {
    const goodsList = this.goodService.goodsList();
    return {
      user: '张三',
      goodsList,
    };
  }
}

骚操作引用

有同学发现, 一个module内直接将另一个module的service申明为当前模块的privaters, 接着在当前模块的service内inject另一个模块的service, 可以正常使用, 但也k可能会带来一些列问题:

  1. 本地实例问题: 如果该 service 在原始模块中也被声明为 provider,那么您实际上在两个不同的模块中创建了该 service 的两个不同实例。这可能导致状态不一致和其他难以追踪的问题。

  2. 循环依赖问题: 如果两个模块相互依赖对方的 providers,这可能导致循环依赖,NestJS 的依赖注入系统可能无法正确解析这些依赖。

  3. 测试与模块化问题: 使用这种模式会降低代码的模块化和可测试性。每个模块应该尽可能地独立,并且易于测试。将其他模块的 providers 声明为本地 private providers 会使得测试当前模块时需要额外关注其他模块的状态和行为。

  4. 代码清晰度问题: 这样的做法可能会让代码阅读者感到困惑,不清楚为什么一个 service 会被声明为另一个模块的 private provider,而不是通过导入原始模块来访问它。

  5. 版本兼容性问题: 随着 NestJS 版本的更新,这种用法可能不再被支持或行为可能发生变化,从而导致潜在的运行时错误。

因此, 最好就是不要出现这样的代码

全局模块

如果这个模块被很多模块依赖了,那每次都要 imports 就很麻烦。

解决方法是直接设置成全局的,它导出的 provider 直接可用

在要exports的模块上通过@Global()申明为全局模块

ts
@Global()
@Module({
  controllers: [GoodsController],
  providers: [GoodsService],
  exports: [GoodsService],
})
export class GoodsModule {}

在其他模块不用imports 就可以直接@Inject使用了

全局模块的问题

全局模块再有的场景下会很方便, 但是一般不推荐, 原因如下:

  1. 很多注入不知道来源(就像vue2中的mixins一样, 很难追踪来源)
  2. 会降低代码可维护性