본 글은 Typescript Programming을 요약한 글입니다.
자세한 내요은 본 책을 읽으시길 바랍니다.

 

 12장에서는 타입스크립트 응용 프로그램을 빌드하고 제품화하는 방법을 살펴본다.

  • 타입스크립트 응용 프로그램을 빌드하는 데 필요한 준비물
  • 서버에서 타입스크립트 응용 프로그램을 빌드하고 실행하기
  • 브라우저에서 타입스크립트 응용 프로그램을 빌드하고 실행하기
  • 타입스크립트를 빌드하고 NPM으로 발행하기

12.1 타입스크립트 프로젝트 빌드하기

 12.1.1 프로젝트 레이아웃

이 책에서는 타입스크립트 소스 코드를 최상위의 src/ 디렉터리에 저장하고, 컴파일한 결과 역시 최상위 dist/ 디렉터리에 저장할 것을 권장한다. 소스 코드와 생성된 코드를 두 개의 최상위 디렉터리에 분리할 수 있어서 다른 도구들과 통합하기가 편해진다. 또한 빌드 과정에서 만들어지는 부산물을 버전 관리 대상에서 제외하기 쉽다는 장점도 있다.

12.1.2 부산물

타입 파일 확장자 tsconfig.json 플래그 기본적으로 생성?
자바스크립트 .js {"emitDeclarationOnly": false} O
소스맵 .js.msp {"sourceMap": true} X
타입 선언 .d.ts {"declaration": true} X
선언 맵 .d.ts.map {"declarationMap": true} X
  1. 자바스크립트 파일 : TSC는 타입스크립트를 자바스크립트로 변환한다.
  2. 소스맵 : 생성된 자바스크립트 코드를 원래 타입스크립트 파일의 행과 열로 연결하는 데 필요한 특별 파일이다. 디버깅에 도움을 주고 자바스크립트 예외의 스택 추적값에서 가리키는 행과 열을 타입스크립트 파일에 매핑해준다.
  3. 타입선언 : 생성된 타입을 다른 타입스크립트 프로젝트에서 이용할 수 있도록 해준다.
  4. 선언 맵 : 타입스크립트 프로젝의 컴파일 시간을 단축하는 데 사용된다.

12.1.3 컴파일 대상 조정

자바스크립트는 매년 규격 명세가 새롭게 릴리스되면서 빠르게 진화할 뿐만 아니라 프로그래머 입장에서는 자신이 구현한 프로그램이 어떤 자바스크립트 번전을 지원하는 플랫폼에서 실행될지 보장할 수 없다. 더 나아가 많은 자바스크립트 프로그램은 단일 형태, 서버와 클라이언트 모두에서 실행할 수 있다.

  • 백엔드 자바스크립트 프로그램을 자신이 제어할 수 있는 서버에서 실행할때는 정확한 어떤 버전으로 실행할지 결정할 수 있다.
  • 백엔드 자바스크립트 프로그램을 오픈 소스로 릴리스한다면 소비자의 플랫폼에서 어떤 버전으로 실행할지 알 수 없다.
  • 자바스크립트를 브라우저에서 실행할 때는 사람들이 어떤 브라우저를 사용할지 알 수 없다.
  • 단일 구조의 자바스크립트 라이브러리를 릴리스한다면 가능한 한 낮은 버전의 Nodejs와 자바스크립트 엔진 및 버전을 동시에 지원해야한다.

모든 환경과 버전을 지원하는 것은 아니지만 코드는 가능하면 최신 버전으로 작성하는 것이 좋다. 이렇게 해도 구 버전 플랫폼에서 동작하게 할 수 있는데 두 가지 방법이 존재한다.

  1. 트랜스파일 : 최신 버전의 자바스크립트를 대상 플랫폼에서 지원하는 가장 낮은 자바스크립트 버전으로 변환한다.
  2. 폴리필 : 실행하려는 자바스크립트 런타임이 포함하지 않는 최신 기능을 폴리필로 제공한다.

TSC는 트랜스파일하는 기능을 기본으로 지원하지만 폴리필은 자동으로 해주지 않는다. TSC에서 대상 환경에 관한 정보를 설정하는 옵션은 세 가지다.

  • Target : 트랜스파일하려는 자바스크립트 버전을 설정한다.
  • module : 대상 모듈 시스템을 설정한다.
  • lib : 타입스크립트 대상 환경에서 어떤 자바스크립트 기능을 지원하는지 알려준다.

응용 프로그램을 실행할 환경의 자바스크립트 버전을 target에 설정하고, 어떤 기능을 쓸지는 lib에 설정한다. module 값은 대상 환경이 NodeJS냐 브라우저냐에 따라 달라지며, 브라우저 환경에서는 어떤 모듈 로더를 쓰는지를 고려해 정해야 한다.

 

target

TSC의 내장 트랜스파일러는 대부분의 자바스크립트 기능을 예전 자바스크립트 버전으로 변환할 수 있다. 트랜스파일 대상을 설정하려면 tsconfig.json 파일을 열어서 target 필드에 원하는 값을 채워 넣는다.

 

lib

 트랜스파일할 때 한 가지 유의사항이 있다. 대상 환경에서 새로운 기능을 지원하지 않으면 폴리필로 직접 제공해야 한다는 사실이다. 이런 폴리필을 우리가 직접 구현할 필요는 없다. core-js 같은 폴리필 라이브러리에서 필요한 기능을 설치하거나, @babel/polyfill을 설치한 . 후 바벨을 이용해 컴파일하면 타입스크립트가 타입을 확인하면서 필요한 폴리필을 자동으로 설치해준다.

 폴리필을 추가했으면 tsconfig.json의 lib 필드를 수정해서 해당 기능이 반드시 지원됨을 TSC에 알리도록 한다. 브라우저에서 실행할 때는 window, document 등 자바스크립트를 브라우저에서 실행할 때 필요한 API들을 사용할 수 있도록 DOM 타입 선언도 활성화해야 한다.

{
	"compilerOptions": {
    	"lib": [
        	"es2015",
            "es2016.array.includes",
            "dom"
        ]
    }
}

12.1.4 소스 맵 활성화

소스 맵은 트랜스파일된 코드를 원본 코드와 이어주는 정보를 제공한다. 대부분의 개발 도구, 에러 리포팅/로깅 프레임워크, 빌드 도구는 소스 맵의 존재를 이미 알고 있다. 보통 빌드 파이프라인은 처음 코드와는 상당히 다른 형태의 코드들을 중간중간 생성하기 때문에 파이프라인 곳곳에서 소스 맵을 활용하여 최종 자바스크립트의 디버깅을 휠씬 수월하게 처리해준다.

 개발 환경에서는 물론, 실제 제품에서도 브라우저와 서버 환경에 소스 맵을 함께 배포하면 좋다. 단점이 있다면 하나, 보안이 요구되는 상황이라면 고객용 브라우저 환경에는 소스 맵을 포함시키지 않는 편이 좋다.

12.1.5 프로젝트 참조

 응용 프로그램의 크기가 커지면 TSC가 타입을 확인하고 코드를 컴파일하는 데 더 오래 걸린다. 이 문제의 해법으로, TSC는 점진적 컴파일과 함께 프로젝트 참조라는 기능을 제공하여 컴파일 시간을 획기적으로 줄인다. 프로젝트 참조는 다음처럼 사용한다.

 1. 타입스크립트 프로젝트를 여러 프로젝트로 분리한다. 함께 수정될 가능성이 큰 코드들을 같은 디렉터리에 저장하는 방식으로 쪼갠다.

 2. 각 프로젝트 디렉터리에 최소한 다음 정보를 포함하는 tsconfig.json을 만든다.

{
	"compilerOptions": {
    	"composite": true,
        "declearation": true,
        "declarationMap": true,
        "rootDir": "."
    },
    "include": [
    	"./**/*.ts"
    ],
    "references": [
    	{
        	"path": "../myReferencedProject",
            "prepend": true
        }
    ],
}
  • composite: TSC에 이 디렉터리는 큰 타입스크립트 프로젝트의 서브 프로젝트임을 알려준다.
  • declaration: TSC에 이 프로젝트의 .d.ts 선언 파일을 생성하라고 지시한다. 각각의 프로젝트는 다른 프로젝트의 선언 파일과 생성된 자바스크립트 파일들에는 접근할 수 있지만, 원본 타입스크립트 파일에는 접근하지 못한다. 이렇게 하여 TSC가 타입을 다시 검사하거나 다시 컴파일해야하는 코드를 선택하는 기준이 만들어진다. 프로젝트 참조가 큰 프로젝트의 빌드 효율을 높여주는 핵심 원리다.
  • declarationMap: TSC에 생성된 타입 선언의 소스 맵을 빌드하라고 지시한다.
  • reference: 이 서브 프로젝트가 의존하는 다른 서브 프로젝트들의 목록이다.
    • 각 참조의 path는 tsconfig.json 파일이 담긴 디렉터리를 가리키거나, TSC 설정파일을 직접 가리켜야 한다.
    • prepend는 참조하는 서브 프로젝트에서 생성한 자바스크립트와 소스 맵을 이 서브 프로젝트에서 생성한 소스와 맵에 이어 붙인다.
  • rootDir: 이 서브 프로젝트가 루트 프로젝트(.)에 상대적으로 컴파일되어야 함을 명시한다.

 3. 아직 다른 서브 프로젝트에서 참조하지 않은 모든 서브 프로젝트를 참조하는 루트 tsconfig.json을 만든다.

{
	"files": [],
    "references": [
    	{
        	"path": "./myProject"
        },
        {
        	"path": "./mySecondProject"
        }
    ]
}

 

 4. 프로젝트를 컴파일할 때 프로젝트 참조를 활용하도록 bulid 플래그를 지정한다.

tsc --bulid # 또는 줄여서 tsc -b

12.1.6 에러 모니터링

타입스크립트는 컴파일 타임의 에러만 경고하므로 사용자가 런타임에 겪을 수 있는 에러를 컴파일 타임에 방지할 수 방법을 찾아야한다. Sentry,Bugsnag 같은 에러 모니터링 도구를 이용하면 런타임 예외를 보고하고 분석하는 데 도움이 된다.

12.2 서버에서 타입스크립트 실행

타입스크립트 코드를 NodeJS 환경에서 실행하려면 tsconfig.json의 module 플래그를 commonjs로 설정하고, 코드를 ES2015 자바스크립트로 컴파일한다. 그러면 ES2015의 import를 require로, export를 module.exports로 변환하여 NodeJS에서 추가 번들 없이 실행할 수 있도록 컴파일해준다. 소스맵도 NodeJS 프로세스에 제공해야 한다.

12.3 브라우저에서 타입스크립트 실행

브라우저에서 타입스크립트를 실행하려면 서버에서 보다 해야할 과정이 많다.

 

 1. 컴파일 하려는 모듈을 선택한다. 라이브러리를 발행할 때는 umd를 사용해 다양한 모듈 번들러와의 호환성을 극대화해야한다. 발행 계획이 없다면 사용하는 모듈 번들러에 맞는 포맷으로 컴파일하면 되니 해당 번들러의 문서를 확인해 본다.

 

 2. 모든 타입스크립트 파일으 한 개의 자바스크립트 파일이나 자바스크립트 파일 집합으로 컴파일하도록 빌드 파이프라인을 설정한다. TSC는 빌드 플러그인이나 웹팩이 제공하는 정도로 영리한 코드 분할을 제공하지 않으므로 자체 기능으로는 부족하다 사실을 느낄 것이다. 그렇기에 처음부터 강력한 빌드 도구를 사용하느 것이 바람직하다.

  • 빌드 도구가 프로젝트 의존성 그래프를 더 정확하게 분석할 수 있도록, 코드를 모듈로 유지하고 코드에서 임의의 의존성을 피한다.
  • 동적 임포트를 이용하여 게으르게 로딩하면 첫 페이지 렌더링 속도를 높일 수 있다.
  • 자동 코드 분할 기능을 사용하면 페이지 로딩이 불필요하게 느려지지 않는다.
  • 페이지 로딩 시간을 측정하는 수단을 마련한다.
  • 제품 빌드를 가능한한 개발 빌드와 같은 형태로 유지한다.
  • 빠진 브라우저 기능을 폴리필로 제공하는 대책을 마련한다.
    • 모든 번들에 폴리필로 제공하는 표준 집합을 마련하거나
    • 브라우저가 지원하는 기능이 무엇이냐에 따라 동적으로 필요한 폴리필을 마련할 수 있다.

12.4 타입스크립트 코드를 NPM으로 발행하기

타입스크립트를 다른 누군가가 사용하도록 컴파일 할때는 다음 규칙들을 따르는 것이 좋다.

  • 자신의 코드를 쉽게 디버깅할 수 있도록 소스 맵을 생성한다.
  • 다른 사람이 우리의 코드르 쉽게 빌드하고 실행할 수 있도록 ES5로 컴파일한다.
  • 어떤 모듈 타입으로 컴파일할지 주의 깊게 결정한다.
  • 다른 타입스크립트 사용자가 우리 코드의 타입을 얻을 수 있도록 타입 선언을 생성한다.

다음과 같은 과정을 거친다.

  1. 먼저 tsc로 타입스크립트를 자바스크립트로 컴파일하고 대응하는 타입선언을 생성한다.
  2. 이어서 NPM에 발행하지 않을 타입스크립트 코드 목록을 .npmignore 파일에 기재하여 패키지가 너무 커지지 않도록한다. 그리고 .gitignore 파일에는 부산물을 제외하게끔 설정해서 깃 저장소가 불필요한 파일로 오염되는 일을 방지한다.
  3. 마지막으로 프로젝트의 package.json에 "types" 필드를 추가해서 타입 선언이 제공될 것임을 알려준다. 스크립트도 추가해서 패키지의 자바스크립트, 타입선언, 소스 맵이 항상 원본 타입스크립트와 같은 최신 버전이 되도록 만든다.

12.5 세 슬래시 지시어

이 지시어는 특별한 포맷의 타입스크립트 주석으로, TSC에 명령을 하달한다. types는 타입 전용 전체 모듈 임포트를 생략할 때 사용하고, amd-module은 생성된 AMD 모듈의 이름을 정할 때 사용한다.

12.5.1 types 지시어

 모듈에서 무언가를 임포트한 코드를 자바스크립트로 컴파일 할 때 타입스크립트가 항상 import나 require 호출을 생성하는 것은 아니다. export한 대상들이 모듈에서 오직 타입 위치에서만 쓰인다면, 타입스크립트는 해당 import 문에 해당하는 자바스크립트 코드를 전혀 생성하지 않는다. 임포트된 대상들이 타입 수준에서만 존재한다고 생각하기 때문이다. 이 기능을 임포트 생략이라고 부른다.

12.5.2 amd-module 지시어

 타입스크립트 코드를 AMD 모듈 포맷으로 컴파일할 때 타입스크립트는 기본값으로 익명 AMD 모듈을 생성한다. 이때 코드에서 amd-module 세 슬래시 지시어를 추가해주면 AMD 모듈에 이름을 지어줄 수 있다.

// <amd-module name="LogService" /> 1
export let LogService = { // 2
	log() {
    	// ...
    }
}
  1. amd-module 지시어에 name 속성을 설정했다.
  2. 나머지 코드는 그대로이다.

TSC로 AMD 모듈 포맷으로 컴파일하면 다음의 자바스크립트 코드가 생성된다.

// <amd-module name="LogService" /> 1
definde('LogeService', ['require','exports'], function(require, exports){ // LogeService라는 이름이 생겼다
	// .... 
})

AMD로 모듈로 컴파일할 떄는 코드를 번들링하거나 디버깅하기 쉽도록 amd-module 지시어를 사용하자.

+ Recent posts