본문 바로가기

main/JS | TS

실제로 타입스크립트의 컴파일 과정은 어떻게 동작할까

 

런타임과 컴파일타임

  • 고수준(high-level) 언어: 사람이 이해하기 쉬운 형식
  • 저수준(low-level) 언어: 컴퓨터가 이해하기 쉬운 형식

개발자가 작성한 고수준 언어의 소스코드는,

컴파일러에 의해 기계어 코드(바이트 코드)로 변환되어 실행이 가능한 프로그램이 된다.

이 단계를 컴파일타임 이라고 부른다.

 

소스코드의 컴파일이 완료되면 프로그램이 메모리에 적재되어 실행되는데,

컴파일 과정을 마친 응용 프로그램이 사용자에 의해 실행되는 과정이다.

이 시간을 런타임 이라고 한다.

 

자바스크립트 런타임

자바스크립트가 실행되는 환경은 대표적으로 크롬이나 사파리 등의 인터넷 브라우저와 Node.js 등이 있다.

자바스크립트 런타임의 주요 구성 요소는 자바스크립트 엔진, 웹 API, 콜백 큐, 이벤트 루프, 렌더 큐가 있다.

 

자바스크립트는 대표적인 인터프리터(interpreter) 언어이지만 때때로 컴파일 단계가 존재한다.

자바스크립트를 해석하고 실행하는 역할을 하는 V8 엔진은 때때로 코드를 최적화하기 위해 컴파일 과정을 거친다.

실행 속도를 향상하기 위한 목적으로 코드를 캐싱하여 이후 실행시간을 단축한다.

 

타입스크립트 컴파일

타입스크립트는 tsc라는 컴파일러를 통해 자바스크립트로 변환된다.

고수준 언어 -> 고수준 언어로 변환되는 것이기 때문에 컴파일이 아닌 트랜스파일이라고 부르기도 한다.

또한 소스코드를 다른 소스코드로 변환하는 것이기에 소스 대 소스 컴파일러(source-to-source compiler)라고 지칭하기도 한다.

 

타입스크립트 컴파일러가 소스코드를 컴파일하여 프로그램이 실행되기까지의 과정은 다음과 같다.

 

  1. 타입스크립트 소스코드를 타입스크립트 AST로 만든다. (tsc)
  2. 타입 검사기가 AST를 확인하여 타입을 확인한다. (tsc)
  3. 타입스크립트 AST를 자바스크립트 소스로 변환한다. (tsc)
  4. 자바스크립트 소스코드를 자바스크립트 AST로 만든다. (런타임)
  5. AST가 바이트 코드로 변환된다. (런타임)
  6. 런타임에서 바이트 코드가 평가되어 프로그램이 실행된다. (런타임)

타입스크립트는 컴파일타임에 타입을 검사하기 때문에 에러가 발생하면 프로그램이 실행되지 않는다.

이러한 특징 때문에 정적 타입 검사기(static type checker)라고 부른다.

 

AST(Abstract Syntax Tree)란?

컴파일러가 소스코드를 해석하는 과정에서 생성된 데이터 구조다.

추상적이라는 이유는 실제 구문에서 나타나는 모든 세세한 정보를 표현하지 않는다는 것을 의미한다.

컴파일러는 어휘적(lexical) 분석과 구문(syntax) 분석을 통해 소스코드를 노드 단위의 트리 구조로 구성한다.

AST 예제와 유즈케이스 설명이 잘 되어있는 글 링크

 

타입스크립트 컴파일러의 구조

타입스크립트 컴파일러는 tsc 명령어로 실행된다. tsconfig.json에 명시된 컴파일 옵션을 기반으로 수행한다.

 

먼저 전체적인 컴파일 과정을 관리하는 프로그램 객체(인스턴스)가 생성된다.

이 프로그램 객체는 컴파일할 타입스크립트 소스 파일과 소스 파일 내에서 임포트된 파일을 불러오는데,

가장 최초로 불러온 파일을 기준으로 컴파일 과정이 시작된다.

 

타입스크립트 컴파일러는 다섯 단계를 거쳐 타입 검사와 자바스크립트 소스 변환을 진행한다.

 

  • 스캐너 (Scanner)

스캐너는 타입스크립트 소스 파일을 어휘적으로 분석(lexical analysis)하여 토큰을 생성하는 역할을 한다.

소스코드를 작은 단위로 나누어 의미 있는 토큰으로 변환하는 작업을 수행한다.

 

  • 파서 (Parser)

파서는 스캐너를 통해 나눠진 토큰 정보를 이용하여 AST를 생성한다.

이 토큰 목록을 활용하여 구문적 분석(syntax analysis)을 수행한다.

실질적인 구조를 노드 단위의 트리 형태로 표현한다. 각각의 노드는 코드상의 위치, 구문 종류, 코드 내용과 같은 정보를 담고 있다.

 

TypeScript AST Viewer로 타입스크립트 소스 파일이 어떻게 AST로 변환되는지 확인할 수 있다.

 

  • 바인더 (Binder)

바인더의 주요 역할은 다음 단계인 체커 단계에서 타입 검사를 할 수 있도록 기반을 마련하는 것이다.

바인더는 타입 검사를 위해 심볼(Symbol)이라는 데이터 구조를 생성한다.

심볼은 이전 단계의 AST에서 선언된 타입의 노드 정보를 저장한다.

 

결과적으로 심볼을 생성하고, 해당 심볼과 그에 대응하는 AST 노드를 연결하는 역할을 수행한다.

 

  • 체커 (Checker)

체커는 파서가 생성한 AST와 바인더가 생성한 심볼을 활용하여 타입 검사를 수행한다.

체커의 소스 크기가 이전 단계인 파서의 소스 크기보다 매우 큰 것으로 보아 타입 검사가 차지하는 비중이 크다는 것을 짐작할 수 있다.

 

checker.ts의 getDiagnostics() 함수를 사용해서 타입을 검증하고 타입 에러에 대한 정보를 보여줄 에러 메시지를 저장한다.

 

  • 이미터 (Emitter)

이미터는 타입스크립트 소스 파일을 변환하는 역할을 한다. (ts 파일을 js, d.ts 파일로 생성한다.)

개발자가 설정한 타입스크립트 설정 파일을 읽어오고, 체커를 통해 코드에 대한 타입 검증 정보를 가져온다.

 

emitter.ts의 emitFiles() 함수를 사용해서 타입스크립트 소스 변환을 진행한다.

 

정리하면 컴파일 과정은 다음과 같다.

 

  1. tsc 명령어를 실행하여 프로그램 객체가 컴파일 과정을 시작한다.
  2. 스캐너는 소스 파일을 토큰 단위로 분리한다.
  3. 파서는 토큰을 이용하여 AST를 생성한다.
  4. 바인더는 AST의 각 노드에 대응하는 심볼을 생성한다. 심볼은 선언된 타입의 노드 정보를 담고 있다.
  5. 체커는 AST를 탐색하면서 심볼 정보를 활용하여 타입 검사를 수행한다.
  6. 타입 검사 결과 에러가 없다면 이미터를 사용해서 자바스크립트 소스 파일로 변환한다.

 

 

출처:

책 우아한 타입스크립트 with 리액트