icon안동민 개발노트

증분 컴파일과 빌드 최적화


 증분 컴파일은 TypeScript 프로젝트의 빌드 성능을 크게 향상시키는 핵심 기능입니다.

 이는 변경된 파일과 그 의존성만을 다시 컴파일하여 전체 빌드 시간을 단축시킵니다.

증분 컴파일의 개념과 영향

  • 개념 : 이전 컴파일 정보를 활용하여 변경된 부분만 다시 컴파일
  • 영향 : 대규모 프로젝트에서 빌드 시간을 크게 단축

증분 컴파일 활성화

 tsconfig.json 설정

{
  "compilerOptions": {
    "incremental": true,
    "tsBuildInfoFile": "./buildcache/front-end.tsbuildinfo"
  }
}
  • incremental : 증분 컴파일 활성화
  • tsBuildInfoFile : 빌드 정보 파일 위치 지정

빌드 캐시 관리

 작동 원리

  1. 이전 빌드 정보를 .tsbuildinfo 파일에 저장
  2. 다음 빌드 시 변경 사항 감지에 활용

 효과적인 관리 전략

  • 빌드 캐시 파일을 버전 관리에서 제외
  • 정기적인 캐시 정리로 불필요한 공간 점유 방지

Watch 모드 활용

 사용법

tsc --watch

 장점

  • 파일 변경 시 자동 재컴파일
  • 개발 중 즉각적인 피드백 제공

 생산성 향상 방안

  • 에디터 통합으로 실시간 오류 감지
  • 핫 리로딩과 결합하여 빠른 개발 사이클 구축

프로젝트 레퍼런스와 증분 컴파일 결합

 설정 예시

{
  "references": [
    { "path": "../common" },
    { "path": "../server" }
  ],
  "compilerOptions": {
    "incremental": true
  }
}

 장점

  • 프로젝트 간 의존성 관리 용이
  • 변경된 프로젝트만 선택적 재빌드

빌드 모드 (-b, --build)

 특징

  • 프로젝트와 그 의존성을 올바른 순서로 빌드
  • 이미 최신 상태인 프로젝트는 건너뛰기

 사용법

tsc -b src

 장점

  • 복잡한 프로젝트 구조에서 효율적인 빌드
  • 증분 빌드와 자동으로 통합

병렬 빌드 및 다중 코어 활용

 전략

  1. 독립적인 모듈을 병렬로 컴파일
  2. 워커 스레드 활용

 도구 활용

  • 타입스크립트 프로젝트 레퍼런스의 내장 병렬 빌드
  • 외부 도구 (예 : Gulp, Webpack) 활용

 예시 (Gulp 사용)

const ts = require('gulp-typescript');
const gulp = require('gulp');
const merge = require('merge2');
 
gulp.task('build', function() {
    const tsProject = ts.createProject('tsconfig.json', { 
        declaration: true,
        incremental: true
    });
    
    const tsResult = tsProject.src()
        .pipe(tsProject());
 
    return merge([
        tsResult.dts.pipe(gulp.dest('dist')),
        tsResult.js.pipe(gulp.dest('dist'))
    ]);
});

잠재적 문제점과 해결 방법

 1. 캐시 불일치

  • 문제 : 빌드 결과가 소스와 일치하지 않음
  • 해결 : 주기적으로 tsc --build --clean 실행

 2. 의존성 변경 감지 실패

  • 문제 : 간접적인 의존성 변경 시 재빌드 안 됨
  • 해결 : 프로젝트 레퍼런스 구조 최적화

 3. 빌드 성능 저하

  • 문제 : 시간이 지남에 따라 빌드 속도 감소
  • 해결 : 정기적인 캐시 정리 및 프로젝트 구조 리팩토링

대규모 모노레포 최적화 사례

 사례 연구 : Microsoft의 TypeScript 컴파일러 프로젝트

  1. 프로젝트 분할 : 컴파일러, 언어 서비스, 테스트 등
  2. 레이어드 구조 : 공통 -> 핵심 -> 특화 모듈
  3. 빌드 스크립트 최적화 : 변경된 부분만 선택적 빌드

 적용 전략

  • 논리적 단위로 프로젝트 분할
  • 공통 모듈 추출 및 의존성 그래프 최적화
  • CI/CD 파이프라인과 증분 빌드 통합

Best Practices

 1. 프로젝트 구조 최적화

  • 모듈 간 의존성 최소화
  • 순환 의존성 제거

 2. 빌드 설정 최적화

  • incrementalcomposite 옵션 활성화
  • 적절한 outDirrootDir 설정

 3. 캐시 관리

  • 빌드 캐시 위치 명확히 지정
  • CI/CD 환경에서 캐시 재사용

 4. 개발 워크플로우 통합

  • Watch 모드와 핫 리로딩 결합
  • 에디터 통합으로 실시간 피드백

 5. 모니터링 및 분석

  • 빌드 시간 정기적 측정
  • 병목 지점 식별 및 개선

 6. 팀 가이드라인

  • 일관된 빌드 스크립트 사용
  • 빌드 성능 영향을 고려한 코드 리뷰

 7. 지속적인 개선

  • 새로운 TypeScript 버전 적용
  • 빌드 도구 및 전략 정기적 검토

 증분 컴파일의 핵심은 변경된 부분만을 선택적으로 재컴파일하는 것입니다.

 Watch 모드와 같은 기능은 개발자의 생산성을 직접적으로 향상시킵니다. 파일 변경 시 자동으로 재컴파일이 이루어져, 개발자가 수동으로 빌드 명령을 실행할 필요가 없어집니다.

 이는 특히 TDD(Test Driven Development) 방식의 개발에서 매우 유용합니다.

 병렬 빌드와 다중 코어 활용은 현대적인 하드웨어의 성능을 최대한 활용할 수 있게 해줍니다.

 그러나 이러한 최적화 기법들을 적용할 때는 잠재적인 문제점들에 대해서도 주의를 기울여야 합니다. 캐시 불일치, 의존성 변경 감지 실패 등의 문제가 발생할 수 있으며, 이를 해결하기 위한 전략을 미리 수립해 두어야 합니다.