Turborepo + Pnpm 을 이용한 모노레포 도입기

Minha Kang·2025년 1월 2일
0
post-thumbnail

Confeti 프로젝트의 모노레포 도입기를 작성합니다.

🤔 모노레포란 ?

모노레포(Mono-repo)는 하나의 저장소(레포지토리)에서 여러 프로젝트를 관리하는 방식을 의미한다.

멀티레포(Multi-repo)와 반대되는 개념으로 볼 수 있고 각각의 장단점이 존재한다.

📚 멀티레포

멀티레포는 프로젝트마다 별도의 저장소가 필요하고, 각 프로젝트가 서로 독립적으로 동작하므로 관리에 용이하다는 장점이 있다. 또한 빌드 시간이 짧고 배포가 빠르게 이루어지게 된다.

하지만 공통 코드(공통 컴포넌트)를 사용하는 경우 각 프로젝트에 코드를 복제해야하고, 이를 해결하기위해 design-system을 사용하려면 npm에 별도로 패키지를 배포해줘야 한다.

이 과정에서 프로젝트마다 CI/CD 파이프라인을 개별적으로 구축해줘야하기에 관리 비용이 증가하게 된다.

🚀 Confeti가 모노레포를 선택한 이유

1️⃣ 확장성


추후에 추가 스프린트를 진행하며 admin, 랜딩 페이지 등 프로젝트가 확장될 예정이다. 랜딩 페이지는 SEO를 위해 Next를 도입할 가능성도 존재하기에 단일 프로젝트보다는 프로젝트 확장성을 염두해둔 모노레포 혹은 멀티레포 세팅이 필요했다.

2️⃣ 단일 조직


각 프로젝트별로 팀이 독립적으로 운영되고, 각각의 컨벤션을 갖는다면 멀티레포를 고려해볼만 했지만 Confeti는 5인의 프론트 개발자, 즉 단일 조직이 여러 프로젝트를 관리하기에 모노레포가 적합하다고 생각했다.

또한 프로젝트 특성상 2주동안 성과를 내야하기에 멀티레포로 구성했을 때의 각 프로젝트에 대해서 Issue/PR을 따로 관리했을 때 발생하는 비용도 만만치 않을 것이라 판단했다.

  • 여러 조직으로 이루어진 Sopt Makers팀의 멀티레포

3️⃣ Design System 관리


마지막으로는 design-system 관리를 용이하게 하기 위함이다.

하나의 저장소에서 디자인 시스템 패키지를 관리함으로써 일관성, 개발 속도, 유지 보수성에서 장점을 얻고자 했다. 모노레포를 사용하면 별도의 배포 없이도 디자인 시스템 내부의 코드를 사용할 수 있기에 해당 과정에서 발생하는 비용을 최소화 할 수 있다.


🎯 모노레포 구성 방법

모노레포를 구성하는 방식은 크게 두가지로 나뉜다.

  1. 모노레포 빌드 시스템 도구 없이 패키지 매니저로 구성
  2. 모노레포 빌드 시스템 도구를 함께 사용

1️⃣ 모노레포 빌드 시스템 도구 없이 패키지 매니저로 구성


npm, yarn, pnpm 모두 workspace를 통해 모노레포를 지원한다. workspace는 자체적인 종속성 트리를 구성하고, 완전히 분리된 프로젝트를 만들 수 있게 한다.

패키지 매니저만으로 모노레포를 구성하면 모노레포 빌드 시스템 도구를 사용하며 발생하는 오버헤드를 줄일 수 있다.

하지만 규모가 커지며 발생하는 빌드 속도를 해결하기 위한 병렬 빌드, 캐싱의 기능을 지원하지 않기에 성능 최적화에서는 단점을 가진다.

2️⃣ 모노레포 빌드 시스템 도구를 함께 사용


규모가 커지거나 여러 애플리케이션이 서로 종속성을 가지는 경우, 모노레포 빌드 시스템 도구를 패키지 매니저와 함께 사용하는 것이 필요하다.

대표적인 도구로는 Turborepo, Nx 등이 있으며, 각 도구는 빌드 속도, 의존성 그래프 분석, 캐시 등 다양한 기능을 제공한다.

이 방식은 빌드 속도 최적화의존성 관계 분석에서 강력한 장점을 가진다. 특히 프로젝트가 커질수록 병렬 빌드, 부분 빌드, 캐시를 활용한 최적화가 필요해지는데, 이를 모노레포 빌드 시스템이 해결해준다.


📌 Turborepo + Pnpm을 선택한 이유

1️⃣ 빌드 속도 최적화


Turborepo는 빌드 캐시병렬 처리 기능을 제공해, 중복된 빌드를 피하고 빠르게 결과물을 생성한다. 예를 들어, 하나의 프로젝트를 빌드할 때 종속된 패키지가 이미 빌드되어 있다면 이를 재활용해 전체 빌드 시간을 단축시킨다.

  • 결과물 재사용: 이미 빌드된 결과물이 있을 경우, 변경된 부분만 빌드
  • 병렬 처리: 여러 애플리케이션을 동시에 빌드해 전체적인 빌드 시간을 크게 단축

2️⃣ 다른 도구에 비해 낮은 러닝커브


Vercel팀에서 개발한 Turborepo는 설정이 간단하고 러닝 커브가 낮아 빠르게 도입할 수 있었다. Nx는 강력하지만 다양한 기능과 복잡한 설정이 필요하며, 학습 비용이 발생할 수 있다.

반면 Turborepo는 직관적인 구성으로 빠르게 사용 가능했다. 또한 공식 문서가 깔끔하게 정리되어 있고, 여러가지 예시도 많이 있어서 사용하기에 가장 편리했다.

https://github.com/vercel/turborepo/tree/main/examples

3️⃣ Pnpm을 선택한 이유


우선 npm과 yarn 1.x 버전은 성능면에서 느릴 뿐더러 의존성 중복 저장 문제를 호이스팅을 통해 해결하기에 유령 의존 현상을 발생시킬 수 있다.

모노레포는 하나의 저장소에서 여러 프로젝트의 의존성을 관리하기에 프로젝트가 서로 다른 프로젝트의 의존성에 의존하는 등 심각한 유령 의존 현상이 발생될 수 있기에 해당 패키지 매니저는 선택사항에서 제외하였다.

https://classic.yarnpkg.com/blog/2018/02/15/nohoist/

Yarn Berry는 PnP 방식으로 node_modules 구조가 사라지기 때문에 초기에 학습 비용이 발생할 수 있고, npm, yarn에 익숙한 팀원들이 적응하는데 오래 걸릴 것이라 판단했다.

반면에 Pnpm(Performent npm)은 npm/yarn 사용자에게 친숙한 환경을 제공하고, 하드링크 및 심볼릭 링크를 통하여 패키지를 설치하므로 의존성 설치 속도와 디스크 사용량 절감에서도 큰 장점을 갖게된다.

추가적으로 Turborepo에서도 Pnpm 사용을 권장하고 있다.


👀 Confeti 모노레포 구조 알아보기

우선 Pnpm 패키지 매니저가 없으면 npm을 통해 설치해주어야한다.
$ npm install -g pnpm
pnpm --version

Pnpm 버전이 정상적으로 출력되면 성공적으로 설치 완료 !

  • pnpm i 를 통해 의존성 설치
  • pnpm dev 를 통해 프로젝트를 실행
  • pnpm add 를 통해 패키지 추가

apps/

  • 실제 배포 및 운영되는 애플리케이션이 위치
  • React로 구성된 Confeti client가 해당 부분에 위치
  • 애플리케이션 별로 독립적인 package.json이 존재할 수 있음

packages/

  • 재사용 가능한 라이브러리공통 모듈이 위치
  • Confeti 디자인 시스템이 해당 부분에 위치
  • 한 번 빌드된 결과물이 캐시로 재사용(Turborepo)

config/

  • 프로젝트에서 사용하는 공통 설정 파일이 위치
  • ESLint 및 TypeScript 설정이 포함되어 있으며, 각 애플리케이션이 해당 설정을 공유

pnpm-workspace.yaml

  • Pnpm 워크스페이스에서 어떤 폴더를 패키지로 인식할지를 설정
  • apps/, packages/,config/ 폴더 아래의 모든 프로젝트를 워크스페이스로 등록

turbo/

  • Turborepo 캐시 및 설정 파일이 저장됨 (.gitignore에 포함)

turbo.json

  • Turborepo의 구성 파일로, 모노레포(Monorepo) 환경에서 빌드, 테스트, 린트, 개발 서버 실행 등 다양한 작업(task)의 실행 방식과 의존성을 정의함

0개의 댓글

관련 채용 정보