최근 NestJS 프로젝트에 SWC(Speedy Web Compiler) 컴파일러를 도입하면서 예상치 못한 문제에 직면했습니다.
TypeORM을 사용하던 중 "ReferenceError: Cannot access 'Order' before initialization" 에러가 발생했습니다.
이 글에서는 이 문제의 원인을 살펴보고, TypeORM의 Relation을 활용해 어떻게 해결했는지 공유하고자 합니다.
NestJS 프로젝트에 SWC(Speedy Web Compiler)를 도입한 후 TypeORM을 사용하던 중, ReferenceError: Cannot access 'Order' before initialization 에러가 발생했습니다. 이 문제는 프로젝트의 특정 엔티티 간에 순환 참조가 존재할 때, SWC의 컴파일 최적화 과정에서 발생하는 오류로 인해 생긴 것으로 보였습니다.
이 에러의 주요 원인은 다음과 같습니다:
변수 호이스팅과 일시적 사각지대(TDZ): SWC 컴파일러가 코드를 변환하는 과정에서 변수 호이스팅과 TDZ 관련 동작이 예상과 다르게 처리될 수 있습니다.
코드 실행 순서: SWC의 최적화로 인해 TypeORM 엔티티의 초기화 순서가 변경될 수 있습니다.
순환 참조: 엔티티 간의 순환 참조가 있을 경우, SWC 컴파일러의 최적화와 충돌할 수 있습니다.
이 문제를 해결하기 위해 TypeORM의 Relation을 활용했습니다. Relation을 사용하면 엔티티 간의 관계를 더 유연하게 정의할 수 있어, SWC 컴파일러의 최적화와도 잘 동작합니다.
1. 관계 재정의
먼저, 문제가 발생한 엔티티들의 관계를 Relation을 사용해 재정의했습니다. 예를 들어, Order와 OrderItem 엔티티가 있다고 가정해 봅시다.
import { Entity, PrimaryGeneratedColumn, OneToMany } from 'typeorm';
import { OrderItem } from './order-item.entity';
@Entity()
export class Order {
@PrimaryGeneratedColumn()
id: number;
@OneToMany(() => OrderItem, orderItem => orderItem.order)
items: OrderItem[];
}
// order-item.entity.ts
import { Entity, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';
import { Order } from './order.entity';
@Entity()
export class OrderItem {
@PrimaryGeneratedColumn()
id: number;
@ManyToOne(() => Order, order => order.items)
order: Order;
}
지연 평가: Relation은 실제로 필요할 때까지 평가되지 않아, 초기화 단계에서의 순환 참조 문제를 피합니다.
프로미스 기반: 지연 로딩을 사용하면 관계가 프로미스로 반환되어, 비동기적으로 데이터를 로드합니다.
함수 래퍼: Relation은 함수로 래핑되어 (예: () => OrderItem), SWC 컴파일러의 최적화 과정에서도 안전하게 처리됩니다.
결과 및 교훈
이러한 변경을 적용한 후, SWC 컴파일러를 사용하면서도 "Cannot access 'X' before initialization" 에러 없이 NestJS와 TypeORM을 원활하게 사용할 수 있게 되었습니다.
이 경험을 통해 얻은 교훈은 다음과 같습니다:
컴파일러 최적화 주의: 새로운 컴파일러나 최적화 도구를 도입할 때는 기존 코드의 동작, 특히 ORM과 같은 복잡한 라이브러리와의 상호작용을 주의 깊게 살펴봐야 합니다.
Relation의 유용성: TypeORM의 Relation은 단순히 데이터베이스 관계를 표현하는 것 외에도, 이런 복잡한 초기화 문제를 해결하는 데 유용합니다.
지연 로딩의 이점: 지연 로딩을 적절히 활용하면 성능 향상뿐만 아니라, 이러한 초기화 관련 문제도 해결할 수 있습니다.
결론
SWC 컴파일러와 NestJS, TypeORM을 함께 사용하면서 마주친 순환 참조 문제를 TypeORM의 Relation을 활용하여 성공적으로 해결했습니다. 이 방법을 통해 코드의 구조를 개선하고, 더 안정적이고 유지보수가 쉬운 애플리케이션을 만들 수 있었습니다. 새로운 도구나 최적화 기술을 도입할 때는 항상 기존 코드와의 호환성을 철저히 검토하고, 문제 해결을 위해 프레임워크나 라이브러리가 제공하는 고급 기능을 적극 활용하는 것이 중요함을 다시 한 번 깨달았습니다.