Item 57 소스맵을 사용하여 타입스크립트 디버깅하기

Debugging

TS 코드를 실행한다는 건, 엄밀히 말하면 "TS 컴파일러가 생성한 JS 코드"를 실행하는 것이다.

  • 컴파일러 뿐 아니라 압축기(minifier)나 전처리기(preprocessor)처럼 기존 코드를 다른 형태로 변형하는 도구들 모두에 해당된다.

  • 이러한 변환 과정이 투명하고 직관적이라면 이상적이겠지만(즉, JS 코드를 볼 필요 없이 TS 코드가 직접 실행되는 것처럼 느껴진다면), 현실은 그렇지 않다.

프로그래밍할 때 디버깅을 위해 디버거을 사용하곤 하는데, 디버거는 런타임에 동작하며, 현재 동작하는 TS 코드(정확히는 JS 코드)가 어떤 과정을 거쳐 만들어진 것인지 알지 못한다. 디버깅을 하면 보게 되는 코드는 전처리기, 컴파일러, 압축기를 거친 JS 코드일 것이다.

이렇게 변환된 JS 코드는 복잡해 디버깅하기 어렵다.

Source Map

이러한 디버깅 문제를 해결하기 위해 브라우저 제조사끼리 협력해 소스맵(source map)이라는 해결책을 내놓았다.

  • 소스맵은 변환된 코드의 위치와 심벌들을 원본 코드의 원래 위치와 심벌들로 매핑한다.

  • 대부분의 브라우저와 많은 IDE가 소스맵을 지원한다.

Browser Debugger

F12 -> Sources로 들어가면 실행되는 JS 소스 코드를 볼 수 있다. 브라우저의 디버거에 접근할 수 있다.

  • 브라우저의 디버거로 들어가보면, 변환된 코드가 매우 복잡한 것을 확인할 수 있다.

  • 오래된 브라우저에서 async-await을 지원하기 위해, TS는 이벤트 핸들러를 상태 머신(state machine)으로 재작성한다.

  • 재작성된 코드는 원본 코드와 동일하게 동작하지만, 코드의 형태는 매우 다른 모습을 띤다.

코드가 복잡하게 변환된다면 소스맵이 필요하다. TS가 소스맵을 생성할 수 있도록 하려면 tsconfig.json에서 sourceMap 옵션을 설정해야 한다.

{
  "compilerOptions": {
    "sourceMap": true
  }
}

이제 컴파일을 실행하면 각 .ts 파일에 대해 .js.js.map 두 개의 파일을 생성한다. 여기서 .js.map 파일이 바로 소스맵이다.

소스맵이 .js 파일과 함께 있으면, 브라우저 디버거에서 index.ts 파일이 보인다! 이제 마치 원본 코드를 조작하는 것처럼 원하는 대로 브레이크포인트를 설정하고 변수를 조사할 수 있다.

  • 디버거의 좌측 파일목록에서 index.ts가 기울림(이탤릭) 글꼴로 나오는데, 이는 웹 페이지에 포함된 '실제 파일'이 아니라는 것을 뜻한다. 실제로는 소스맵을 통해 TS처럼 보이는 것 뿐이다.

  • 또한, index.js.map 파일이 index.ts 파일의 (1) 참조를 포함(브라우저가 네트워크를 통해 로드)하거나, 또는 파일의 내용을 (2) 인라인으로 포함(별도 요청이 불필요)하도록 설정할 수도 있다.

소스맵에 대해 알아야 할 몇 가지 사항들

  • TS와 함께 번들러(bundler)나 압축기(minifier)를 사용하고 있다면, 번들러나 압축기가 각자의 소스맵을 생성하게 된다.

    • 이상적인 디버깅 환경을 위해서는 생성된 JS가 아닌 원본 TS 소스로 매핑되도록 해야 한다.

    • 번들러가 기본적으로 TS를 지원한다면 별도 설정 없이 잘 동작해야 한다. 그렇지 않다면 번들러가 소스맵을 인식할 수 있도록 추가 설정이 필요하다.

  • 상용(production) 환경에 소스맵이 유출되고 있는지 확인해야 한다.

    • 디버거를 열지 않는 이상은 소스맵이 로드되지 않으므로 실제 사용자에게 성능 저하는 발생하지 않지만, 소스맵에 원본 코드의 인라인 복사본이 포함되어 있다면 공개해선 안될 내용이 들어 있을 수 있다.

    • 저질 주석이나 내부 버그 추적을 위한 URL을 공개할 필요는 없다.

  • NodeJS 프로그램의 디버깅에도 소스맵을 사용할 수 있다.

    • 보통 편집기가 자동 인식하거나 NodeJS 프로세스를 브라우저 디버거와 연결하면 된다.

    • 자세한 내용은 NodeJS 문서를 참고하자. (StackOverflow 참고)

Summary

  • 원본 코드가 아닌 변환된 JS 코드를 디버깅하지 말자. (알아보기 어렵다.) 소스맵을 사용해 런타임에서 원본 TS 코드를 이용해 디버깅하자.

  • 소스맵이 최종적으로 변환된 코드에 완전히 매핑되었는지 확인하자.

  • 소스맵에 원본 코드가 그대로 포함되도록 설정되어 있을 수도 있으니, production에서는 공개되지 않도록 설정(tsconfig)을 확인하자.

Last updated