Programming

타입스크립트의 "프로젝트 참조(reference)"

WANJIN 2022. 8. 5. 19:08
반응형

개발하고 있는 스페이스원(SpaceONE) 콘솔 프로젝트에 모노레포를 도입하면서 TypeScript의 reference 기능을 알게되었습니다.

그러나 역시 최소한의 정보를 가지고 뛰어들면 삽질의 여정을 만나게 됩니다.

그래서 다시 공식 문서로 돌아와 하나하나 뜯어보며 이해하기로 결심하고 이 글을 씁니다.

이 글은 Typescript 의 공식 문서에서 References 와 관련된 부분을 개인적으로 이해할 목적으로 의역한 글입니다.

마지막 부분에 당장 불필요해서(이해가 안되어서) 빼먹은게 있긴 한데…. 언젠가 업데이트 할 날이 오겠죠 ㅠㅠ


타입스크립트의 프로젝트 참조가 뭔가요?

프로그램을 더 작은 조각으로 구성할 수 있는 TypeScript 3.0의 새로운 기능입니다.

이렇게 하면

  • 빌드 시간을 크게 개선하고
  • 구성 요소(compoents) 간의 논리적 분리가 가능하고
  • 새롭고 더 나은 방식으로 코드를 구성할 수 있습니다.

tsc용 --build 플래그도 함께 작동합니다.

왜 필요하죠? 어떨 때 좋나요?

프로젝트 참조(references)가 프로그램을 더 잘 구성하는 데 어떻게 도움이 되는지 봅시다.

두 개의 모듈(converter 및 unit)과 각각에 해당하는 테스트 파일이 있는 프로젝트가 있다고 합시다.

/
├── src/
│   ├── converter.ts
│   └── units.ts
├── test/
│   ├── converter-tests.ts
│   └── units-tests.ts
└── tsconfig.json
// converter-tests.ts
import * as converter from "../converter";
assert.areEqual(converter.celsiusToFahrenheit(0), 32);

이전에는 단일 tsconfig 파일을 사용하는 경우, 이 구조를 사용하는 것이 다소 어색했습니다.

  • 구현 파일에서 테스트 파일을 가져올 수 있었습니다.
  • output 폴더 이름에 src를 표시하지 않고(아마도 이렇게 해주기 싫었을 것) test와 src를 동시에 빌드하는 것은 불가능했습니다.
  • 구현 파일의 내부만 변경하면 새로운 오류가 발생하지 않더라도 테스트를 다시 type check해야 했습니다.
  • 테스트만 변경하면 아무 것도 변경되지 않았더라도 구현 파일도 다시 type check해야 했습니다.

여러 tsconfig 파일을 사용하여 이러한 문제 중 일부를 해결할 수 있지만 새로운 문제가 나타났을 겁니다.

  • 내장된 최신 확인(built-in up-to-date checking) 기능이 없으므로 항상 tsc를 두 번 실행하게 됩니다.
  • tsc를 두 번 호출하면 더 많은 시작 시간 오버헤드가 발생합니다.
  • tsc -w는 한 번에 여러 config 파일에 대하여 실행할 수 없습니다.

프로젝트 참조는 이러한 모든 문제 등을 해결할 수 있습니다.

어떻게 쓰나요? 어떻게 동작하죠?

tsconfig.json 파일에는 새로운 최상위 속성인 references가 있습니다. 참조할 프로젝트를 지정하는 객체의 배열입니다.

{
    "compilerOptions": {
        // The usual
    },
    "references": [
        { "path": "../src" }
    ]
}

references의 각 path 속성은 tsconfig.json 파일이 포함된 디렉토리 또는 tsconfig 파일 자체(이름이 있을 수 있음)를 가리킬 수 있습니다.

프로젝트를 참조하면 다음과 같은 새로운 일이 발생합니다.

  • 참조된 프로젝트에서 모듈을 가져오면, 대신 출력 선언 파일(.d.ts)이 로드됩니다.
  • 참조된 프로젝트가 outFile을 생성하는 경우, 출력 파일 .d.ts 파일의 선언이 이 프로젝트에서 표시됩니다.
  • 빌드 모드(아래 참조)는 필요한 경우 참조된 프로젝트를 자동으로 빌드합니다.

여러 프로젝트로 분리하면 type check 및 컴파일 속도를 크게 향상시키고 편집기를 사용할 때 메모리 사용량을 줄이고 프로그램의 논리적 그룹화 시행을 개선할 수 있습니다.

참조되는 프로젝트에 동작하도록 설정해줄게 있나요?

참조된 프로젝트에는 composite 설정이 활성화되어 있어야 합니다.

이 설정은 TypeScript가 참조된 프로젝트의 출력을 찾을 위치를 빠르게 결정할 수 있도록 하는 데 필요합니다.

이 플래그를 활성화하면 몇 가지 사항이 변경됩니다.

  • 명시적으로 설정하지 않은 경우 rootDir 설정은 기본적으로 tsconfig 파일이 포함된 디렉토리로 설정됩니다.
  • 모든 구현 파일은 include 패턴과 일치하거나 files 배열에 나열되어야 합니다. 이 제약 조건을 위반하면 tsc는 지정되지 않은 파일을 알려줍니다.
  • declaration 도 켜야 합니다.

참조된 프로젝트들도 IDE의 탐색기능이 지원되나요?

declarationMap

선언 소스 맵(declaration source map)에 대한 지원도 됩니다.

declarationMap 을 활성화하면 "Go to Definition" 및 이름 바꾸기와 같은 IDE의 기능을 사용할 수 있어요.

종속된 파일들을 앞에 추가하려면?(이거 아직 이해가 안됨 ㅠㅠ)

references에서 에서 prepend 옵션을 사용하여 종속성(dependency)의 출력 파일들(output)을 앞에 추가할 수도 있습니다.

"references": [
   { "path": "../utils", "prepend": true }
]

프로젝트 앞에 추가하면 현재 프로젝트의 출력 위에 프로젝트의 출력이 포함됩니다. 모든 출력 파일(.js, .d.ts, .js.map, .d.ts.map)이 올바르게 내보내집니다.

tsc는 이 프로세스를 수행하기 위해, 디스크의 기존 파일만 사용합니다.

그러면 일부 프로젝트의 출력이 결과 파일에 두 번 이상 있기 때문에 올바른 출력 파일을 생성할 수 없는 프로젝트를 생성할 수 있습니다.

예를 들어:

   A
  ^ ^
 /   \\
B     C
 ^   ^
  \\ /
   D

이 상황에서 각 참조 앞에 추가하지 않는 것이 중요합니다.

D의 출력에 A의 두 복사본이 있게 되기 때문입니다. 이는 예기치 않은 결과를 초래할 수 있습니다.

참조한 프로젝트를 빌드하려면 어떻게 하는게 좋죠?

종속 프로젝트(다른 프로젝트들을 참조한 프로젝트)는 참조 프로젝트의 빌드된 .d.ts 파일을 사용합니다.

때문에, 특정 빌드 output으로 확인해야 합니다. 혹은 복제한 후 프로젝트를 빌드해야 합니다.

가짜 오류를 보지 않고 편집기에서 프로젝트를 탐색할 수 있게 하려면요.

기존 빌드 워크플로우와의 호환성을 유지하기 위해 --build 스위치를 사용하여, 호출하지 않는 한 tsc가 종속성을 자동으로 빌드하지 않도록 할 수 있어요.

--build에 대해 자세히 알아보겠습니다.

추가된 --build 알아보기

TypeScript 프로젝트를 위한 스마트한 증분 빌드(incremental builds)입니다.

3.0에서는 tsc와 함께 --build 플래그를 사용할 수 있습니다.

이것은 단순한 컴파일러보다 빌드 오케스트레이터처럼 작동합니다.

tsc --build(줄여서 tsc -b)를 실행하면 다음이 수행됩니다.

  • 참조된 모든 프로젝트 찾기
  • 최신 상태인지 감지
  • 올바른 순서로 오래된 프로젝트 빌드

tsc -b에 여러 config 파일의 경로를 제공할 수 있습니다(예: tsc -b src test).

원하는 수만큼 config 파일을 구성할 수 있습니다.

 > tsc -b                            # Use the tsconfig.json in the current directory
 > tsc -b src                        # Use src/tsconfig.json
 > tsc -b foo/prd.tsconfig.json bar  # Use foo/prd.tsconfig.json and bar/tsconfig.json

명령줄에서 전달하는 config 파일의 순서는 중요하지 않습니다.

tsc는 종속성이 항상 먼저 빌드되도록, 필요한 경우 파일을 재정렬합니다.

tsc -b와 관련된 몇 가지 플래그도 있습니다.

  • --verbose: 진행 상황을 설명하기 위해 자세한 로깅을 출력합니다(다른 플래그와 결합될 수 있음).
  • --dry: 수행할 작업을 표시하지만 실제로는 아무 것도 빌드하지 않습니다.
  • --clean: 지정된 프로젝트의 출력을 삭제합니다(--dry와 결합될 수 있음).
  • --force: 모든 프로젝트가 오래된 것(out of date)처럼 작동합니다.
  • --watch: 감시 모드(--verbose를 제외한 플래그와 결합할 수 없음)

주의 사항이 있습니다.

일반적으로 tsc는 noEmitOnError가 켜져 있지 않는 한, 구문 또는 타입 에러가 있는 경우 출력물(.js 및 .d.ts)을 생성합니다.

증분 빌드 시스템에서 이 작업을 수행하는 것은 매우 나쁩니다. 그렇기 때문에, 오래된 종속성 중 하나에 새로운 오류가 있는 경우 한 번만 볼 수 있었을 겁니다. 후속 빌드가 현재의 최신 프로젝트 빌드를 건너뛰기 때문이죠.

이러한 이유로 tsc -b는 모든 프로젝트에 대해 noEmitOnError가 활성화된 것처럼 효과적으로 작동합니다.

빌드 출력(.js, .d.ts, .d.ts.map 등)을 확인하려는 경우, 소스 제어 도구(IDE)가 로컬 사본과 원격 사본 사이의 타임스탬프를 보존하는지 여부에 따라, 특정 소스 제어 작업 후에 --force 빌드를 실행해야 할 수도 있습니다.

  • MSBuild (이건 걍 번역만…)이렇게 하면 자동 증분 빌드와 cleaning이 활성화됩니다.일부 팀은 tsconfig 파일이 짝을 이루어 관리되는 프로젝트와 동일한 암시적 그래프 순서를 갖는 msbuild 기반 워크플로를 설정했습니다. 솔루션이 이와 같으면 프로젝트 참조와 함께 tsc -p와 함께 msbuild를 계속 사용할 수 있습니다. 이들은 완전히 상호 운용 가능합니다.
  • <TypeScriptBuildMode>참</TypeScriptBuildMode>
  • tsconfig.json / -p와 마찬가지로 기존 TypeScript 프로젝트 속성은 존중되지 않습니다. 모든 설정은 tsconfig 파일을 사용하여 관리해야 합니다.
  • msbuild 프로젝트가 있는 경우, 프로젝트 파일에 다음을 추가하여 빌드 모드를 활성화할 수 있습니다.
 
반응형