테마
빌드 시스템 도구의 필요성
패키지 매니저만으로는 대규모 모노레포를 효율적으로 운영할 수 없으며, 태스크 오케스트레이션과 캐싱을 제공하는 빌드 시스템 도구가 필수적이다.
학습 목표
- 패키지 매니저만으로 모노레포를 운영할 때 발생하는 한계를 이해한다
- 태스크 오케스트레이션이 왜 필요한지 설명할 수 있다
- 캐싱과 변경 감지가 빌드 성능에 미치는 영향을 파악한다
- 빌드 시스템 도구가 제공하는 핵심 기능을 분류할 수 있다
- 주요 빌드 시스템 도구(Lerna, NX, Rush, TurboRepo)의 존재와 포지셔닝을 안다
1. 패키지 매니저만으로 충분한가?
npm, Yarn Classic, Yarn Berry, pnpm은 모두 워크스페이스(workspace) 기능을 갖추고 있다. 이 기능을 사용하면 각 패키지에 독립적으로 명령을 수행하거나, 전체 패키지를 순회하며 스크립트를 실행할 수 있다.
패키지 매니저 워크스페이스가 제공하는 것:
| 기능 | 설명 |
|---|---|
| 의존성 설치 | 전체 워크스페이스의 의존성을 한 번에 설치 |
| 호이스팅 | 공통 의존성을 루트로 끌어올려 중복 제거 |
| 심볼릭 링크 | 로컬 패키지 간 참조를 자동으로 연결 |
| 스크립트 실행 | 특정 또는 전체 패키지에서 npm 스크립트 실행 |
작은 규모의 모노레포에서는 이것만으로도 충분히 동작한다. 패키지가 3~5개 수준이라면 특별한 문제를 느끼지 못할 수 있다.
하지만 모노레포는 운영하면서 기하급수적으로 커진다. 패키지가 수십, 수백 개로 늘어나면 패키지 매니저만으로는 해결할 수 없는 문제들이 발생한다.
2. 패키지 매니저의 한계: 의존 관계와 빌드 순서
모노레포에서 패키지 간 의존 관계가 존재할 때, 빌드와 테스트의 실행 순서가 매우 중요해진다.
문제점:
- C가 변경되면 B도, A도 재빌드해야 한다. 순서는 반드시 C -> B -> A여야 한다.
- B만 변경되면 A만 재빌드하면 된다. C는 건드릴 필요가 없다.
- 사람이 항상 정확한 순서를 기억해서 빌드하기 어렵다.
- 혹은 매번 C -> B -> A 전체를 빌드하는 스크립트를 만들어야 한다.
- 패키지가 수십 개로 늘어나면 의존 관계를 파악하는 것 자체가 복잡해진다.
패키지 매니저의 워크스페이스 기능은 "모든 패키지에서 build를 실행해라" 정도까지는 할 수 있지만, **"어떤 패키지가 변경되었는지 파악하고, 영향받는 패키지만 올바른 순서로 빌드해라"**는 할 수 없다.
3. 태스크 오케스트레이션이란?
태스크 오케스트레이션은 여러 패키지에 걸쳐 있는 작업들의 실행 순서와 병렬 처리를 자동으로 관리하는 것이다.
빌드 시스템 도구는 다음을 자동으로 처리한다:
- 의존 그래프 분석: 패키지 간 의존 관계를 파악하여 방향성 비순환 그래프(DAG)를 구성한다.
- 변경 감지: git diff 등을 활용하여 어떤 패키지의 코드가 변경되었는지 감지한다.
- 실행 순서 결정: 의존 관계에 따라 올바른 순서(위상 정렬)로 태스크를 실행한다.
- 병렬 실행: 의존 관계가 없는 태스크는 동시에 병렬로 실행하여 시간을 단축한다.
- 캐시 히트 시 건너뛰기: 변경이 없는 패키지의 태스크는 캐시된 결과를 재사용한다.
4. 캐싱: 빌드 성능의 핵심
캐싱은 빌드 시스템 도구가 제공하는 가장 중요한 성능 최적화 기능이다. 변경되지 않은 패키지의 빌드 결과를 저장해두고, 다음 빌드 시 재사용한다.
캐싱이 없을 때:
모노레포에 패키지가 50개 있고, 개발자가 한 패키지만 수정했다고 가정하자. 캐싱이 없으면 50개 패키지 전체를 다시 빌드해야 한다. 각 빌드에 10초가 걸린다면 총 500초(약 8분)가 소요된다.
캐싱이 있을 때:
빌드 시스템 도구가 각 패키지의 입력(소스 코드, 설정 파일, 의존성 버전 등)을 해시로 저장한다. 다음 빌드 시 해시가 동일하면 이전 결과를 그대로 사용한다. 위 예시에서 1개 패키지만 변경되었으므로 실제 빌드는 1개 + 영향받는 패키지 몇 개만 수행하면 된다.
캐싱의 두 가지 수준:
| 수준 | 설명 | 제공 도구 |
|---|---|---|
| 로컬 캐싱 | 개발자의 로컬 머신에 캐시를 저장. 같은 머신에서 반복 빌드 시 효과적 | Lerna, NX, Rush, TurboRepo 모두 지원 |
| 리모트 캐싱 | 클라우드에 캐시를 저장. CI/CD나 다른 팀원이 캐시를 공유. CI 빌드 시간을 극적으로 단축 | NX Cloud, Vercel Remote Cache, Rush(Azure 등) |
5. 변경 감지: 무엇을 다시 빌드할 것인가
변경 감지는 어떤 패키지가 마지막 빌드 이후 변경되었는지를 파악하는 기능이다. 대부분의 빌드 시스템 도구는 git을 활용하여 변경 감지를 수행한다.
변경 감지의 동작 방식:
- 현재 커밋과 이전 커밋(또는 기준 브랜치)의 diff를 계산한다.
- 변경된 파일이 속한 패키지를 식별한다.
- 해당 패키지에 의존하는 다른 패키지까지 영향 범위를 확장한다.
- 영향받는 패키지에 대해서만 태스크를 실행한다.
"affected" 명령의 가치:
NX의 nx affected, Lerna의 lerna changed, TurboRepo의 필터 기능 등은 모두 이 변경 감지를 기반으로 한다. CI/CD 파이프라인에서 이 기능을 활용하면, PR에서 변경된 패키지와 그 영향권의 패키지만 빌드/테스트하므로 CI 시간을 대폭 줄일 수 있다.
6. 빌드 시스템 도구가 제공하는 핵심 기능 분류
6.1 필수 기능 (우리가 집중할 것)
| 기능 | 설명 | 왜 중요한가 |
|---|---|---|
| 태스크 실행 | 단일 또는 전체 패키지에서 스크립트를 실행 | 빌드, 테스트, 린트 등 모든 작업의 기본 |
| 태스크 오케스트레이션 | 의존 순서를 지켜 태스크를 실행하고 병렬화 | 올바른 빌드 순서 보장 + 성능 최적화 |
| 캐싱 | 변경 없는 패키지의 결과를 재사용 | 빌드 시간을 수 분에서 수 초로 단축 |
6.2 부가 기능 (도구마다 차이)
| 기능 | 설명 | 제공 도구 |
|---|---|---|
| 버전 관리 / 배포 | 패키지 버전 증가, npm 게시, 변경 로그 생성 | Lerna, Rush |
| 코드 생성 | 보일러플레이트 코드나 프로젝트 스캐폴딩 자동 생성 | NX, TurboRepo |
| 의존 그래프 시각화 | 패키지 간 의존 관계를 인터랙티브 그래프로 표시 | NX |
| 모듈 경계 강제 | 패키지 간 접근 규칙을 린트 수준에서 강제 | NX |
| 분산 태스크 실행 | CI에서 여러 에이전트에 태스크를 분산 | NX Cloud |
| 정책 관리 | 의존성 승인, 일관된 버전 적용 등 거버넌스 | Rush |
7. 주요 빌드 시스템 도구 비교
프론트엔드 생태계에서 가장 널리 사용되는 빌드 시스템 도구 네 가지를 비교한다.
| 비교 항목 | Lerna | NX | Rush | TurboRepo |
|---|---|---|---|---|
| 포지셔닝 | 오리지널 모노레포 관리 도구 | 스마트 빌드 시스템 | 대규모 모노레포 매니저 | 고성능 빌드 시스템 |
| 운영 주체 | Nrwl (NX 팀) | Nrwl | Microsoft | Vercel |
| 핵심 강점 | 버전 관리, npm 게시 | 풍부한 기능, 프로젝트 그래프 | 정책 관리, 대규모 팀 지원 | 단순함, 성능 |
| 캐싱 | NX 기반 | 자체 (로컬 + 클라우드) | git 기반 | 자체 (로컬 + Vercel) |
| 설정 파일 | lerna.json + nx.json | nx.json + project.json | rush.json | turbo.json |
| 패키지 매니저 | npm, yarn, pnpm | npm, yarn, pnpm | pnpm (기본) | npm, yarn, pnpm (pnpm 권장) |
| 학습 곡선 | 낮음 | 중간~높음 | 높음 | 낮음 |
| 국내 레퍼런스 | 많음 | 보통 | 적음 | 증가 중 |
8. 빌드 시스템 도구 도입 시 고려 사항
빌드 시스템 도구는 분명 유용하지만, 도입 자체가 비용을 수반한다.
도입의 이점:
- 빌드/테스트 시간 단축으로 생산성 향상
- 패키지 간 의존 관계의 자동 관리
- CI/CD 파이프라인 최적화
- 패키지 분석 및 시각화 도구 제공
도입의 비용:
- 도구에 대한 학습 곡선
- 설정 파일 관리 부담
- 도구 업데이트 추적 필요
- 도구에 대한 의존성 (lock-in)
적절한 도입 시점:
- 패키지가 5개 이상으로 늘어나기 시작할 때
- 전체 빌드 시간이 체감될 정도로 길어질 때
- CI/CD에서 불필요한 빌드로 인한 비용이 증가할 때
- 여러 팀이 하나의 모노레포에서 협업할 때
핵심 정리
| 핵심 개념 | 요약 |
|---|---|
| 패키지 매니저의 한계 | 워크스페이스 기능만으로는 빌드 순서 관리, 캐싱, 변경 감지가 불가능하다 |
| 태스크 오케스트레이션 | 의존 관계를 분석하여 올바른 순서로, 가능하면 병렬로 태스크를 실행한다 |
| 캐싱 | 변경 없는 패키지의 빌드 결과를 재사용하여 빌드 시간을 극적으로 단축한다 |
| 변경 감지 | git을 기반으로 변경된 패키지와 영향받는 패키지를 자동으로 파악한다 |
| 로컬 vs 리모트 캐시 | 로컬 캐시는 개인 머신, 리모트 캐시는 팀/CI 전체에서 공유한다 |
| 도구 선택 | 팀 규모, 프로젝트 복잡도, 학습 곡선 등을 종합적으로 고려해야 한다 |
| 비용 대비 효과 | 도구 도입 비용이 있으므로, 프로젝트 규모가 충분할 때 도입하는 것이 효과적이다 |
다음 단계
이번 장에서는 빌드 시스템 도구가 왜 필요한지, 그리고 어떤 핵심 기능을 제공하는지 개괄적으로 살펴보았다. 다음 장에서는 모노레포 관리 도구의 원조인 Lerna에 대해 자세히 알아보고, 태스크 실행과 버전 관리를 직접 실습한다.