我在使用Nx的 monorepo 设置中使用NestJs,NextJs 作为客户端。我的基本架构是拥有包含特定域(身份验证、用户、帖子等)的所有逻辑(客户端、服务器和 api 代码)的模块,然后拥有这些模块使用的服务(CssService、DbService、JwtService、ValidationService 等) . 文件夹结构看起来像这样(我已经为这个演示删除了不必要的桶/Nx lib 文件):
modules
auth
api
signup
client
service-methods-and-properties
signup.error-messages.ts
signup.fields.ts
signup.form.logic.ts
signup.form.ui.tsx
signup.form.tsx
signup.mutation.generated.ts
signup.mutation.gql
signup.service.ts
signup.types.ts
server
service-methods-and-properties
signup.input.ts
signup.logic.ts
signup.response.ts
signup.service.ts
signup.types.ts
client
pages
signup
signup.page.tsx
server
auth.module.ts
auth.resolver.ts
services
db
client
db.service
server
db.service
在我的 NestJs 身份验证解析器 (modules/auth/server/auth.resolver) 中,我导入 SignupServerService 以供注册处理程序使用:
import { SignupServerService } from '../api/signup/server';
@Resolver()
export class AuthResolver {
constructor(private readonly signupServerService: SignupServerService) {}
@Mutation(() => SignupServerService.Response)
async signup(
@Args('input') input: SignupServerService.Input
): Promise<typeof SignupServerService.Response.prototype> {
return this.signupServerService.logic(input);
}
}
这是注册服务器服务:
@Injectable()
export class SignupServerService {
constructor(
private readonly gqlServerService: GqlServerService,
protected readonly dbServerService: DbServerService,
protected readonly jwtServerService: JwtServerService
) {}
static readonly Input = SignupInput;
static readonly Response = SignupResponse;
readonly logic = signupLogic;
}
但是,这有几个问题,我有一些相关的问题:
该代码有效,但我在我的 resolver 中得到了这行的几个 TS 错误,如果我直接从文件中
@Args('input') input: SignupServerService.Input
使用它就会消失,而不是通过类静态访问它。错误是和SignupInput
signup.input.ts
SignupServerService
'SignupServerService' only refers to a type, but is being used as a namespace here.ts(2702)
Parameter 'input' of public method from exported class has or is using private name 'SignupServerService'.ts(4073)
支持问题 1,我在 上使用了一些静态属性,
SignupServerService
因此我可以传递SignupServerService.Response
给@Mutation
装饰器 args,因为以下内容不起作用@Mutation(() => this.signupServerService.Response)
。我想知道为什么这不起作用?我使用静态方法将属性传递给装饰器参数的模式是最好的方法吗?我应该使用 TS 命名空间而不是静态类方法还是有更好的方法来处理这个?此外,我听说静态方法会导致单元测试出现问题,应该避免吗?NestJs 文档的日志记录部分提到了这一点,但还不足以得出任何结论:“这种技术虽然简单,但并未对 MyLogger 类使用依赖注入。这可能会带来一些挑战,尤其是对于测试,并限制 MyLogger 的可重用性”
这让我想到了一个关于在 monorepo 中使用 NestJs 的更普遍的问题。我经常需要在一些 NestJs 代码和一些 React 代码之间共享一个类/服务(例如我的自定义 JwtService - 注意,这不是 NestJs 内置的 JwtService)。自然,功能性反应组件不使用 DI 系统,因此要访问 JwtService 上的属性,我需要将它们设为静态(例如
JwtService.ACCESS_TOKEN_COOKIE_NAME
),这意味着在 JwtService 类中复制属性(例如static ACCESS_TOKEN_COOKIE_NAME = ACCESS_TOKEN_COOKIE_NAME; ACCESS_TOKEN_COOKIE_NAME = ACCESS_TOKEN_COOKIE_NAME
),或者不要使用静态方法并在我的反应代码中手动实例化服务(例如const { ACCESS_TOKEN_COOKIE_NAME } = new JwtService()
)。但是,如果服务具有我必须手动提供给类构造函数参数的依赖项,则这将变得不可用,特别是如果依赖项仅由 NestJs 代码中使用的方法使用(例如const { ACCESS_TOKEN_COOKIE_NAME } = new JwtService(new SomeDependencyNotNeededForReact())
)。那么在这种情况下最好的解决方案是什么?