Quick Flow
packages/
core/
tsconfig.json
app/
tsconfig.json
tsconfig.json{
"files": [],
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/app" }
]
}tsc --build
tsc --build --clean| 상황 | 먼저 볼 기준 |
|---|---|
| 모노레포 패키지가 서로 참조한다 | project references |
| 전체 타입 검사 시간이 길다 | tsc --build 증분 빌드 |
| 패키지 경계를 강제하고 싶다 | 각 패키지별 tsconfig.json |
| 참조 대상이 빌드되지 않는다 | composite, declaration 확인 |
독립적으로 빌드할 수 있는 package·layer 경계가 있을 때 project reference를 둡니다. 참조 대상에는 composite: true가 필요하고 tsc --build가 dependency 순서를 관리하지만, 작은 단일 앱에 tsconfig를 억지로 쪼개면 설정과 편집기 비용만 늘어납니다.
무엇을 해결하나
project references는 TypeScript 프로젝트를 여러 작은 단위로 나누는 기능입니다. 루트 tsconfig.json에서 하위 프로젝트를 references로 선언하면 tsc --build가 의존 순서를 계산하고 필요한 프로젝트부터 빌드합니다.
{
"references": [
{ "path": "../core" }
]
}큰 저장소에서 하나의 tsconfig만 쓰면 작은 변경에도 전체 타입 검사가 반복되기 쉽습니다. 프로젝트를 경계별로 나누면 패키지 간 계약은 .d.ts 출력으로 연결되고, 이미 최신인 프로젝트는 다시 검사하지 않는 흐름을 만들 수 있습니다.
composite 설정
참조되는 프로젝트는 composite: true가 필요합니다. 이 옵션은 TypeScript가 해당 프로젝트의 입력과 출력을 추적할 수 있도록 몇 가지 제약을 강제합니다. 대표적으로 구현 파일은 include나 files에 포함되어야 하고, declaration 출력이 필요합니다.
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true,
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}declarationMap을 켜면 editor에서 참조 프로젝트의 .d.ts가 아니라 원본 소스로 이동하기 쉬워집니다. 모노레포에서 "Go to Definition" 품질을 유지하려면 같이 검토할 만합니다.
build mode
tsc --build 또는 tsc -b는 project references를 위한 빌드 모드입니다. 일반 tsc -p처럼 단일 config만 보는 흐름이 아니라, 참조 그래프를 따라 필요한 프로젝트를 순서대로 빌드합니다.
tsc -b
tsc -b packages/core packages/app
tsc -b --verbose빌드 산출물이나 증분 상태를 초기화해야 할 때는 --clean을 사용합니다.
tsc -b --clean
tsc -bCI에서는 루트에서 tsc -b --pretty false처럼 실행해 전체 타입 경계를 검증하고, 로컬에서는 변경 패키지 중심으로 실행하는 방식을 둘 수 있습니다.
여러 패키지가 서로 의존하는 모노레포, 앱과 공유 라이브러리를 함께 관리하는 저장소, 서버와 클라이언트가 공통 타입 패키지를 공유하는 구조에서 효과가 큽니다.
packages/core -> packages/api -> apps/web단일 앱 규모가 작고 패키지 경계가 뚜렷하지 않다면 project references가 오히려 설정 부담을 늘릴 수 있습니다. 먼저 include, exclude, paths, 빌드 캐시만으로 충분한지 확인한 뒤 도입하는 편이 좋습니다.
주의할 점
project references는 path alias의 대체재가 아닙니다. alias는 import 경로를 읽기 쉽게 만드는 설정이고, references는 TypeScript 프로젝트 간 빌드 순서와 타입 출력 경계를 만드는 설정입니다.
참조 프로젝트가 내부 소스를 직접 import하게 두면 경계가 흐려질 수 있습니다. 패키지 entry point, declaration 출력, package manager workspace 설정까지 함께 맞춰야 실제 런타임 경계와 타입 경계가 같은 방향으로 움직입니다.
// 피하는 편이 좋은 내부 경로 참조
import { parse } from "@repo/core/src/internal/parse";
// 공개 entry point를 통한 참조
import { parse } from "@repo/core";참고 링크
2 sources