Skip to content

monorepo 변경 후 DataSource 주입 실패 (작성 중)

ez edited this page Nov 17, 2024 · 7 revisions

monorepo 변경 후 DataSource 주입 실패 해결 과정

이슈

이슈 #185

현재 저희 프로젝트에서는 typeORM을 사용하여 데이터베이스에 접근하고 있습니다.

그리고 Repository 계층을 커스텀하기 위해 다음과 같이 Repository를 extends하여 사용 중입니다.

import { DataSource, Repository } from 'typeorm';
import { Node } from './node.entity';
import { Injectable } from '@nestjs/common';

@Injectable()
export class NodeRepository extends Repository<Node> {
  constructor(private dataSource: DataSource) {
    super(Node, dataSource.createEntityManager());
  }

  async findById(id: number): Promise<Node | null> {
    return await this.findOneBy({ id });
  }
}

그리고 기존 구조에서 turbo를 사용하여 monorepo 구조로 변경하였습니다.

변경한 이후 각 workspace(frontend, backend) 별로 node_modules가 존재하고 root에도 node_modules가 존재합니다.

그런데 이렇게 monorepo 구조로 변경한 뒤 DataSource가 주입되지 않는 이슈가 발생했습니다.

이 이슈의 원인을 파악하기 위해서 @nestjs/typeorm과 typeorm의 차이점에 대해 알아야 합니다.

@nestjs/typeorm과 typeorm의 차이점

TypeORM은 Node.js용 객체 관계형 매핑(ORM) 패키지이고 엔티티와 테이블 간 매핑을 담당합니다.

@nestjs/typeorm은 nest.js의 DI 컨테이너와 호환되도록 typeorm의 인스턴스를 관리합니다.

@nestjs/typeorm은 typeorm에 의존하기 때문에 nest.js에서 typeorm을 사용하려면 두 패키지를 함께 설치해야 합니다.

yarn add @nestjs/typeorm typeorm

DataSource 주입받는 과정

DataSource를 주입받기 위해서 TypeOrmModule의 forRoot 메소드를 통해 데이터베이스에 대한 설정을 해야 합니다.

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'root',
      database: 'test',
      entities: [],
      synchronize: true,
    }),
  ],
})
export class AppModule {}

다음은 공식 문서의 forRoot 메소드에 대한 설명입니다.

The forRoot() method supports all the configuration properties exposed by the DataSource constructor from the TypeORM package. In addition, there are several extra configuration properties described below.

위 설명을 통해 @nestjs/typeorm 패키지는 typeorm 패키지에 의존하는 것을 알 수 있습니다.

위 설정이 끝난다면 프로젝트 내 모든 곳에서 typeorm의 DataSource와 EntityManager를 주입받을 수 있습니다.

그리고 Repository를 사용하기 위해서 해당 모듈에서 forFeature를 사용하여 어떠한 엔티티에 대한 레포지토리를 사용할 지 알려줘야 합니다.

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { User } from './user.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  providers: [UsersService],
  controllers: [UsersController],
})
export class UsersModule {}

위 설정을 마쳤다면 Repository를 커스텀 할 수 있습니다.

현재 저희 프로젝트에서 사용하는 엔티티는 Node, Page, Edge가 있고 모두 Repository를 커스텀해서 사용 중입니다.

아래는 저희 프로젝트에서 사용하는 NodeRepository입니다.

import { DataSource, Repository } from 'typeorm';
import { Node } from './node.entity';
import { Injectable } from '@nestjs/common';

@Injectable()
export class NodeRepository extends Repository<Node> {
  constructor(private dataSource: DataSource) {
    super(Node, dataSource.createEntityManager());
  }

  async findById(id: number): Promise<Node | null> {
    return await this.findOneBy({ id });
  }
}

설정을 모두 마쳤다면 DataSource는 의존성 주입이 성공적으로 이루어져야 합니다.

실제로 위 코드에서 DataSource는 의존성 주입이 잘 되었으나 monorepo로 변경한 다음 의존성 주입이 이루어지지 않았습니다.

monorepo 구조

package.json에 workspace를 정의하여 apps 디렉토리 내부의 모든 디렉토리는 workspace로 인식합니다.

{
  "name": "octodocs",
  "version": "1.0.0",
  "main": "index.js",
  "repository": "https://github.com/boostcampwm-2024/web15-OctoDocs.git",
  "author": "ez <[email protected]>",
  "license": "MIT",
  "scripts": {
    "dev": "turbo run dev",
    "build": "turbo run build",
    "start": "node apps/backend/dist/main.js",
    "lint": "turbo run lint",
    "test": "turbo run test"
  },
  "dependencies": {
    "turbo": "^2.3.0"
  },
  "private": true,
  "workspaces": [
    "apps/*"
  ],
  "packageManager": "[email protected]"
}

그리고 turbo를 사용하였습니다.

turbo를 설치 후 패키지를 설치하면 각 workspace 내부에 node_modules가 생성되고

개발 문서

⚓️ 사용자 피드백과 버그 기록
👷🏻 기술적 도전
📖 위키와 학습정리
🚧 트러블슈팅

팀 문화

🧸 팀원 소개
⛺️ 그라운드 룰
🍞 커밋 컨벤션
🧈 이슈, PR 컨벤션
🥞 브랜치 전략

그룹 기록

📢 발표 자료
🌤️ 데일리 스크럼
📑 회의록
🏖️ 그룹 회고
🚸 멘토링 일지

Clone this wiki locally