Front-end Developer
모노레포 with Turbo (2023/03/12) 본문
모노레포 란?
모노레포란 같은 레포지토리에서 서로 다른 프로젝트를 관리하는 소프트웨어 개발 전략. 각 프로젝트를 서로 다른 레포지토리에서 관리하는 전략과 비교했을 때 코드 재사용, 외부 의존성 관리, 모든 프로젝트를 아우르는 리팩토링.
- 코드 재사용, 외부 의존성 관리, 모든 프로젝트를 아우르는 리팩토링 측면에서 장점이 있다.
- 소수의 FE 엔지니어가, 다수의 FE 프로젝트를 개발 및 운영해야 하는 상황에서 유리하다.
- FE 프로젝트 소스를 한곳에서 관리함으로써 소스의 변경사항을 보다 쉽게 파악할 수 있고, 신규 입사자가 합류했을 때 개발환경을 세팅하는 데 비용을 줄일 수 있다.
- 이미 개발해 둔 공통 UI 컴포넌트 라이브러리와 같이 모듈화된 코드를 여러 프로젝트에서 재사용 할 수 있다.
- 코드 정적 분석 및 테스트 도구를 공통적으로 적용함으로써 코드의 최소 품질을 유지할 수 있다.
Turborepo 란?
Vercel 에서 개발 및 운영하고 있는 Javascript / Typescript 를 위한 모노레포 빌드 시스템.
Turborepo 는 증분 빌드(Incremental build), 원격 캐싱, 병렬 처리 기법을 통해 빌드 성능을 끌어올리고, Pipeline 의 쉬운 설정과 profiling, trace 등 다양한 시각화 기능을 제공해 관리 편의성을 높였다.
Core Concepts
캐싱
이전에 실행한 파일 및 로그를 캐싱해 만약 현재 실행 태스크에 이미 완료한 작업이 있다면 이 것을 건너뜀. 작업 실행 시간을 효과적으로 줄일 수 있다.
yarn turbo run build
- 캐시들이 저장되는 구조?(Turborepo는 빌드해야 할 항목을 파악하기 위해 타임스탬프를 확인하고 활용하는 대신 파일의 내용에 따른 hash 정책을 사용한다.) 이 hash 값들은 아래 이미지와 같이
node_modules/.cache/turbo
하위에 hash로 구분된 스냅샷 폴더와 매칭된다.이렇게 모든 작업에 대한 캐싱을 진행하므로, 변화된 부분만 재빌드하고 나머지는 캐싱한 것을 사용해 작업 속도를 높일 수 있다.
{ "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { "outputs": ["dist/**", ".next/**"], "dependsOn": ["^build"] }, "test": { "outputs": [], // leave empty to only cache logs "dependsOn": ["build"] } } }
turbo run build test
하면node_modules/.cache/turbo
에서 캐시된 작업물을 확인할 수 있다. - Configuring Cache Outputs
-
- 빌드를 하면
/app
하위 패키지들의.turbo
디렉터리에 각각 로그 파일이 생기고 이 로그에는 해당 빌드에 대한 hash가 저장된다.
원격 캐싱
위의 캐시는 로컬환경에서만 유효하다. Turborepo 는 이 한계를 극복하는 원격 캐싱이라는 강력한 기능을 제공한다.
더 빠른 빌드를 위해 빌드 캐시를 클라우드에 올려서 팀원 및 CI/CD 시스템이 공유해 사용할 수 있어 대규모 프로젝트에서 다수의 팀이 협업하는 환경에서 개발 효율성을 높일 수 있다.
( 베타 상태, Vercel 클라우드를 활용하기 때문에, Vercel 의 계정이 필요하다.)
Pipeline Package Task
Pipeline 은 각 패키지의 package.json 스크립트(태스크) 간 작업 관계를 정의한다. 이를 통해 새로 들어온 개발자도 작업 관계를 쉽게 이해할 수 있다.
Pipeline 설정은 Turborepo turbo.json 에서 확인할 수 있다.
{
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"]
},
"test": {
"dependsOn": ["^build"]
},
"deploy": {
"dependsOn": ["build", "test", "lint"]
},
"lint": {}
}
}
Pipeline 으로 인해 Turborepo 의 스케줄러는 기존 모노레포에 비해 성능이 강력하다. 한 번에 한 태스크씩 수행된느 기존 방식과 다르게 의존성이 없는 작업은 유휴 CPU 에서 실행되기 때문에 빌드 시간이 긴 경우에 작업 성능이 비약적으로 높아진다.
A, B, C 세 개의 패키지로 구성된 프로젝트가 있다. A와 C는 B에 의존한다.
lint
, build
, test
, deploy
작업을 순차적으로 수행한다고 했을 때 Lerna의 경우에 A, C 패키지는 B의 build
가 끝날 때까지 build
를 수행할 수 없다.
이에 반해 Turborepo는 build
에 의존 관계가 없는 test
작업이 병렬적으로 수행된다.