Turborepo로 모노레포 프로젝트 구성하기

오형근·2023년 5월 28일
1

Typescript

목록 보기
15/15
post-thumbnail

곧 참여할 프로젝트가 Turborepo와 pnpm을 활용한 모노레포로 구성되어 있기 때문에, 이전까지 Turborepo에 대한 개념을 짚고 넘어가고자 아티클을 작성하게 되었다!

Turborepo

Turborepo는 Vercel에서 인수한 JS/TS 기반의 모노레포 빌드 시스템이다. 최근 화두가 되었던 MSA와 여러 개의 MSA를 효율적으로 관리하기 위한 방법으로 모노레포가 떠오르게 되었는데, turborepo를 통해 이를 효율적으로 구축하는 방법에 대해 알아보자.

Vercel과 Turbo가 말하는 Turborepo의 역할은 모노레포 환경 내에서 개발자가 개발에 더 집중할 수 있도록 빌드 도구를 제공하는 것에 있는데, 다양한 툴을 활용한 고급 빌드 시스템을 구축하는 일련의 복잡한 과정들을 Turborepo가 대신 수행해 줌으로써 개발자가 온전히 개발에 더 집중할 수 있도록 도와준다.

Turborepo의 특징

Turborepo 공식문서에서 말하고 있는 Turborepo의 특징은 아래 사진과 같다.

1. Incremental builds

이는 작업 상황을 캐싱해두어 이미 계산이 완료된 작업은 건너 뛰는 것을 말한다. 여기서 목표는 빌드 횟수를 1회로 고정하는 것이다.

2. Content-aware hasing

파일의 변경 여부를 기반으로 스탬프를 찍고 이를 해싱한다. 즉 특정 시점을 기준으로 파일을 복원하는 것이 아닌 파일 변경점을 기준으로 변경된 파일만 빌드하게 된다.

3. Cloud caching

클라우드 빌드 캐시를 팀원 및 CI/CD와 공유한. 이를 이용해 클라우드 환경에서도 빠른 빌드를 제공하게 된다.

4. Parallel execution

모든 코어를 사용하여 병렬적으로 작업을 수행하는 것을 목표로 한다. 지정된 task 단위로 의존성을 판단하여 최대한 병렬적인 작업을 진행한다.

아래는 타 모노레포 빌드 툴인 lerna와 비교한 그림인데, parallel execution을 적용하여 4가지의 작업을 효율적으로 처리하여 시간을 단축한 것을 확인할 수 있다.

5. Task Pipelines

task 간의 연결을 정의해서 빌드를 어떻게 언제 실행할지 판단하고 최적화한다.

이게 무슨 말인지 간략하게 짚어보기 위해, Turbo에서 예시로 들어준 아래 상황을 살펴보자.

위 그림에서 우리는 세 가지 workspace와 각 workspace에서 수행해야할 세 가지 task가 주어져있다.

여기서 apps/webapps/doc은 각각 packages/shared의 공통 코드를 사용하는데, 이를 위해서 우리는 packages/shared가 우선적으로 빌드된 뒤에 남은 두 task가 수행되어야할 필요가 있다. 이와 같이 여러 task가 주어진 상황에서 turborepo는 최적화를 위해 우선적으로 처리해야할 task를 판단하고 수행 순서를 정렬한다는 특징을 가진다.

6. Zero Runtime Overhead

Turborepo는 런타임 코드와 소스 맵을 다루지 않으므로 런타임 단계에서 파악하지 못한 리스크가 불거질 위험이 없다. 이로 인해 런타임 단계에서 발생하는 리소스 오버헤드가 발생할 위험이 없다.

7. Pruned subsets

빌드에 필수적인 요소만으로 모노 레포의 하위 집합을 생성해 Paas의 배포 속도를 향상시킨다.

8. JSON Configuration

별도의 코드 작업 없이 JSON 설정만으로도 터보를 사용 가능하다.

{ "baseBranch": "origin/main", "pipeline": { "build": { ... } } }

9. Profile in browser

빌드 프로필로 빌드 과정을 시각화하면 과정을 쉽게 확인하고 병목 지점을 쉽게 찾을 수 있다.

위의 특징 중에서도 빌드 과정을 분화하고 캐싱하는 Incremental builds, task 단위로 의존성을 판단하여 병렬적인 작업을 수행하도록 하는 parallel execution, task 간 연결을 정의하여 빌드를 언제, 어떻게 실행해야 할지 판단하고 최적화하는 Task Pipelines가 좀 더 강조되는 사용 이유가 되는 것 같다.

Monorepo는 어떻게 작동할까?

우선적으로 monorepo의 주요 구성 요소는 workspace이다.

빌드하는 각각의 app, package들은 자체 workspace, package.json이 존재한다.

apps/docs/package.json

{
  "dependencies": {
    "shared-utils": "workspace:*"
  }
}

확인해보면 docs의 workspace는 shares-utils에 의존하고 있다는 것을 확인할 수 있다.

Turborepo 구성하기

사실 모노레포 구성에는 symbolic linkcontent addressable file store방식을 사용하는 pnpm을 패키지 매니저로 구성하는 게 권장되지만,,, 이번 아티클에서는 yarn으로 진행했다.

npx create-turbo@latest

위 명령어를 입력하고 기다리면 turborepo를 기반으로 하는 모노레포가 구성된다. 여기서 apps의 경우 실제 서비스 로직을 구성하는 코드가 들어가게 되고, packages의 경우 공통 ui나 util 함수 같은 재사용 로직들이 들어가게 된다.

Turbo에서 제공하는 보일러 플레이트에는 기본적으로 예시 프로젝트인 docs와 web이 존재한다. 각각 우리가 packages폴더에서 제공되는 공통 컴포넌트인 Button을 사용하고 있는데, 이를 확인하고 렌더링해보자.

기본적으로 Next 버전 13.4을 기준으로 하므로 안정화가 수순을 밟고 있는 app 디렉토리를 통해 nested routing이 진행된다는 점!!

루트 디렉토리에서

yarn
yarn dev

를 실행해보자.

그러면 일련의 과정이 수행된 후, 각각 3000번 포트와 3001번 포트에서 프로젝트가 열리는 것을 알 수 있다.

그리고 이를 살펴보면,



이렇게 두 포트에서 모두 정상적으로 프로젝트가 열려있는 것을 확인할 수 있다.

마무리

지금까지 간단하게 turborepo를 활용해서 모노레포 프로젝트를 구성하는 방법과 그 특징에 대해 짚어보았다.
앞으로 모노레포 프로젝트를 다루면서 알게 된 것들을 간간히 이곳에 적어보려고 한다!!!

Reference

Turborepo 공식문서
Turborepo로 모노레포 개발 경험 향상하기(linecorp)

profile
https://nohv.site

0개의 댓글