MSBuild에서의 컴파일러 옵션

MSBuild에서의 컴파일러 옵션 (Compiler Options in MSBuild)

MSBuild 기반 프로젝트(예: ASP.NET Core 프로젝트)에서 TypeScript를 쓸 때는 설정을 tsconfig.json으로 할지, 프로젝트 설정으로 할지 두 가지 방법이 있어요. 어떤 방식이 언제 어울리는지, 그리고 프로젝트 파일에서 어떤 옵션을 쓸 수 있는지 함께 살펴볼게요.

출처: TypeScript 핸드북 - Compiler Options in MSBuild

개요 (Overview)

ASP.NET Core 프로젝트처럼 TypeScript를 활용하는 MSBuild 기반 프로젝트가 있을 때, TypeScript를 두 가지 방식으로 구성할 수 있어요. tsconfig.json을 통하거나, 프로젝트 설정을 통하는 방식이죠.

tsconfig.json 사용하기

가능하면 프로젝트에 tsconfig.json을 사용하는 것을 권장합니다. 기존 프로젝트에 추가하려면, 최신 버전의 Visual Studio에서 "TypeScript JSON Configuration File"이라고 불리는 새 항목을 프로젝트에 추가하세요.

tsconfig.json은 그다음부터 파일과 설정 같은 TypeScript 고유의 빌드 정보에 대한 진실의 원천(source of truth)으로 사용될 거예요. TSConfig가 어떻게 동작하는지 여기서 배울 수 있고, 포괄적인 참조는 여기 있습니다.

프로젝트 설정 사용하기

TypeScript 설정을 프로젝트의 설정 안에서 정의할 수도 있어요. 이는 .csproj의 XML을 편집해 빌드가 어떻게 동작할지 설명하는 PropertyGroup들을 정의하는 방식으로 이루어집니다.

<PropertyGroup>
  <TypeScriptNoEmitOnError>true</TypeScriptNoEmitOnError>
  <TypeScriptNoImplicitReturns>true</TypeScriptNoImplicitReturns>
</PropertyGroup>

흔한 TypeScript 설정에 대한 일련의 매핑이 있어요. 이 설정들은 TypeScript CLI 옵션에 직접 대응하며, 더 이해하기 쉬운 프로젝트 파일을 작성하는 데 도움을 줍니다. 각 매핑의 값과 기본값에 대한 더 많은 정보는 TSConfig reference를 사용할 수 있어요.

CLI 매핑 (CLI Mappings)

MSBuild Config Name TSC Flag
<TypeScriptAllowJS> --allowJs

JavaScript 파일이 프로그램의 일부가 되도록 허용합니다. 이 파일들에서 에러를 얻으려면 checkJS 옵션을 사용하세요.

<TypeScriptRemoveComments> --removeComments

주석 출력을 비활성화합니다.

<TypeScriptNoImplicitAny> --noImplicitAny

암시된 any 타입을 가진 표현식과 선언에 대한 에러 보고를 활성화합니다..

<TypeScriptGeneratesDeclarations> --declaration

프로젝트의 TypeScript 및 JavaScript 파일로부터 .d.ts 파일을 생성합니다.

<TypeScriptModuleKind> --module

어떤 모듈 코드가 생성되는지 지정합니다.

<TypeScriptJSXEmit> --jsx

어떤 JSX 코드가 생성되는지 지정합니다.

<TypeScriptOutDir> --outDir

모든 출력 파일을 위한 출력 폴더를 지정합니다.

<TypeScriptSourceMap> --sourcemap

출력된 JavaScript 파일을 위한 소스 맵 파일을 생성합니다.

<TypeScriptTarget> --target

출력되는 JavaScript의 JavaScript 언어 버전을 설정하고 호환되는 라이브러리 선언을 포함합니다.

<TypeScriptNoResolve> --noResolve

import, require 또는 <reference>가 TypeScript가 프로젝트에 추가해야 하는 파일의 수를 늘리는 것을 허용하지 않습니다.

<TypeScriptMapRoot> --mapRoot

디버거가 생성된 위치 대신 맵 파일을 찾을 위치를 지정합니다.

<TypeScriptSourceRoot> --sourceRoot

디버거가 참조 소스 코드를 찾을 루트 경로를 지정합니다.

<TypeScriptCharset> --charset

더 이상 지원되지 않습니다. 초기 버전에서는 파일을 읽을 텍스트 인코딩을 수동으로 설정했습니다.

<TypeScriptEmitBOM> --emitBOM

출력 파일의 시작 부분에 UTF-8 바이트 오더 마크(BOM)를 출력합니다.

<TypeScriptNoLib> --noLib

기본 lib.d.ts를 포함한 라이브러리 파일을 전부 포함하는 것을 비활성화합니다.

<TypeScriptPreserveConstEnums> --preserveConstEnums

생성된 코드에서 const enum 선언을 지우는 것을 비활성화합니다.

<TypeScriptSuppressImplicitAnyIndexErrors> --suppressImplicitAnyIndexErrors

인덱스 시그니처가 없는 객체를 인덱싱할 때 noImplicitAny 에러를 억제합니다.

<TypeScriptNoEmitHelpers> --noEmitHelpers

컴파일 출력에서 __extends 같은 사용자 정의 헬퍼 함수의 생성을 비활성화합니다.

<TypeScriptInlineSourceMap> --inlineSourceMap

출력된 JavaScript 안에 소스맵 파일을 포함합니다.

<TypeScriptInlineSources> --inlineSources

출력된 JavaScript 안의 소스맵에 소스 코드를 포함합니다.

<TypeScriptNewLine> --newLine

파일 출력을 위한 줄바꿈 문자를 설정합니다.

<TypeScriptIsolatedModules> --isolatedModules

각 파일이 다른 import에 의존하지 않고 안전하게 트랜스파일될 수 있도록 보장합니다.

<TypeScriptEmitDecoratorMetadata> --emitDecoratorMetadata

소스 파일의 데코레이트된 선언에 대한 design-type 메타데이터를 출력합니다.

<TypeScriptRootDir> --rootDir

소스 파일 안의 루트 폴더를 지정합니다.

<TypeScriptExperimentalDecorators> --experimentalDecorators

TC39 stage 2 초안 데코레이터에 대한 실험적 지원을 활성화합니다.

<TypeScriptModuleResolution> --moduleResolution

TypeScript가 주어진 모듈 스펙시파이어에서 파일을 어떻게 찾는지 지정합니다.

<TypeScriptSuppressExcessPropertyErrors> --suppressExcessPropertyErrors

객체 리터럴 생성 중 초과 프로퍼티 에러 보고를 비활성화합니다.

<TypeScriptReactNamespace> --reactNamespace

createElement에 대해 호출되는 객체를 지정합니다. 이는 react JSX 출력을 대상으로 할 때만 적용됩니다.

<TypeScriptSkipDefaultLibCheck> --skipDefaultLibCheck

TypeScript에 포함된 .d.ts 파일의 타입 검사를 건너뜁니다.

<TypeScriptAllowUnusedLabels> --allowUnusedLabels

사용되지 않는 레이블에 대한 에러 보고를 비활성화합니다.

<TypeScriptNoImplicitReturns> --noImplicitReturns

함수에서 명시적으로 반환하지 않는 코드 경로에 대한 에러 보고를 활성화합니다.

<TypeScriptNoFallthroughCasesInSwitch> --noFallthroughCasesInSwitch

switch문에서 빠져나가는(fallthrough) 경우에 대한 에러 보고를 활성화합니다.

<TypeScriptAllowUnreachableCode> --allowUnreachableCode

도달 불가능한 코드에 대한 에러 보고를 비활성화합니다.

<TypeScriptForceConsistentCasingInFileNames> --forceConsistentCasingInFileNames

import의 대소문자가 올바른지 보장합니다.

<TypeScriptAllowSyntheticDefaultImports> --allowSyntheticDefaultImports

모듈에 기본 export가 없을 때 'import x from y'를 허용합니다.

<TypeScriptNoImplicitUseStrict> --noImplicitUseStrict

출력된 JavaScript 파일에 'use strict' 지시문을 추가하는 것을 비활성화합니다.

<TypeScriptLib> --lib

대상 런타임 환경을 설명하는 번들 라이브러리 선언 파일 집합을 지정합니다.

<TypeScriptBaseUrl> --baseUrl

베어 스펙시파이어(bare specifier) 모듈 이름을 해석할 기준 디렉터리를 지정합니다.

<TypeScriptDeclarationDir> --declarationDir

생성된 선언 파일의 출력 디렉터리를 지정합니다.

<TypeScriptNoImplicitThis> --noImplicitThis

thisany 타입이 주어질 때 에러 보고를 활성화합니다.

<TypeScriptSkipLibCheck> --skipLibCheck

모든 .d.ts 파일의 타입 검사를 건너뜁니다.

<TypeScriptStrictNullChecks> --strictNullChecks

타입 검사 시 nullundefined를 고려합니다.

<TypeScriptNoUnusedLocals> --noUnusedLocals

지역 변수가 읽히지 않을 때 에러 보고를 활성화합니다.

<TypeScriptNoUnusedParameters> --noUnusedParameters

함수 파라미터가 읽히지 않을 때 에러를 냅니다.

<TypeScriptAlwaysStrict> --alwaysStrict

'use strict'가 항상 출력되도록 합니다.

<TypeScriptImportHelpers> --importHelpers

파일별로 포함하는 대신, 프로젝트당 한 번 tslib에서 헬퍼 함수를 가져오는 것을 허용합니다.

<TypeScriptJSXFactory> --jsxFactory

React JSX 출력을 대상으로 할 때 사용할 JSX 팩토리 함수를 지정합니다. 예: 'React.createElement' 또는 'h'

<TypeScriptStripInternal> --stripInternal

JSDoc 주석에 @internal이 있는 선언의 출력을 비활성화합니다.

<TypeScriptCheckJs> --checkJs

타입 검사되는 JavaScript 파일에서 에러 보고를 활성화합니다.

<TypeScriptDownlevelIteration> --downlevelIteration

반복(iteration)에 대해 더 규격을 준수하지만 장황하고 성능이 낮은 JavaScript를 출력합니다.

<TypeScriptStrict> --strict

모든 엄격 타입 검사 옵션을 활성화합니다.

<TypeScriptNoStrictGenericChecks> --noStrictGenericChecks

함수 타입에서 제네릭 시그니처의 엄격한 검사를 비활성화합니다.

<TypeScriptPreserveSymlinks> --preserveSymlinks

심볼릭 링크를 실제 경로(realpath)로 해석하는 것을 비활성화합니다. node의 같은 이름 플래그와 대응됩니다.

<TypeScriptStrictFunctionTypes> --strictFunctionTypes

함수를 할당할 때 파라미터와 반환 값이 서브타입 호환인지 확인합니다.

<TypeScriptStrictPropertyInitialization> --strictPropertyInitialization

선언되었지만 생성자에서 설정되지 않은 클래스 프로퍼티를 검사합니다.

<TypeScriptESModuleInterop> --esModuleInterop

CommonJS 모듈 가져오기 지원을 쉽게 하기 위해 추가 JavaScript를 출력합니다. 이는 타입 호환을 위해 allowSyntheticDefaultImports를 활성화합니다.

<TypeScriptEmitDeclarationOnly> --emitDeclarationOnly

JavaScript 파일이 아닌 d.ts 파일만 출력합니다.

<TypeScriptKeyofStringsOnly> --keyofStringsOnly

keyof가 문자열, 숫자, 심볼이 아닌 오직 문자열만 반환하게 합니다. 레거시 옵션입니다.

<TypeScriptUseDefineForClassFields> --useDefineForClassFields

ECMAScript 표준을 준수하는 클래스 필드를 출력합니다.

<TypeScriptDeclarationMap> --declarationMap

d.ts 파일용 소스맵(sourcemaps)을 생성합니다.

<TypeScriptResolveJsonModule> --resolveJsonModule

.json 파일 가져오기를 활성화합니다.

<TypeScriptStrictBindCallApply> --strictBindCallApply

bind, call, apply 메서드의 인자가 원래 함수와 일치하는지 확인합니다.

<TypeScriptNoEmitOnError> --noEmitOnError

타입 검사 에러가 보고되면 파일 출력을 비활성화합니다.

추가 플래그 (Additional Flags)

MSBuild 시스템이 인자를 TypeScript CLI에 직접 전달하므로, 위의 매핑에 없는 특정 플래그를 제공하기 위해 TypeScriptAdditionalFlags 옵션을 사용할 수 있어요.

예를 들어, 다음은 noPropertyAccessFromIndexSignature를 켭니다.

<TypeScriptAdditionalFlags> $(TypeScriptAdditionalFlags) --noPropertyAccessFromIndexSignature</TypeScriptAdditionalFlags>

디버그/릴리스 빌드 (Debug and Release Builds)

PropertyGroup 조건(condition)을 사용해 서로 다른 설정 집합을 정의할 수 있어요. 예를 들어, 운영(production)에서는 주석과 소스맵을 제거하는 것이 흔한 작업이에요. 이 예시에서는 서로 다른 TypeScript 설정을 가진 디버그/릴리스 프로퍼티 그룹을 정의합니다.

<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
  <TypeScriptRemoveComments>false</TypeScriptRemoveComments>
  <TypeScriptSourceMap>true</TypeScriptSourceMap>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)' == 'Release'">
  <TypeScriptRemoveComments>true</TypeScriptRemoveComments>
  <TypeScriptSourceMap>false</TypeScriptSourceMap>
</PropertyGroup>

<Import
    Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets"
    Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets')" />

ToolsVersion

프로젝트 파일의 <TypeScriptToolsVersion>1.7</TypeScriptToolsVersion> 프로퍼티 값은 빌드에 사용할 컴파일러 버전을 식별합니다(이 예시에서는 1.7). 이를 통해 서로 다른 머신에서 같은 버전의 컴파일러로 프로젝트를 빌드할 수 있어요.

TypeScriptToolsVersion을 지정하지 않으면, 머신에 설치된 최신 컴파일러 버전으로 빌드할 거예요.

더 새로운 버전의 TS를 사용하는 사용자는 첫 로드 시 프로젝트를 업그레이드하라는 프롬프트를 볼 거예요.

TypeScriptCompileBlocked

다른 빌드 도구(예: gulp, grunt 등)로 프로젝트를 빌드하고, 개발과 디버깅 경험에는 VS를 사용한다면, 프로젝트에 <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>를 설정하세요. 이러면 모든 편집 지원은 그대로 받되, F5를 눌렀을 때 빌드는 하지 않아요.

TypeScriptEnableIncrementalMSBuild (TypeScript 4.2 Beta 이상)

기본적으로 MSBuild는 프로젝트의 소스 파일이 마지막 컴파일 이후 갱신된 경우에만 TypeScript 컴파일러를 실행하려고 시도합니다. 하지만 이 동작이 문제를 일으키는 경우, 예를 들어 TypeScript의 incremental 옵션이 활성화되어 있을 때는, <TypeScriptEnableIncrementalMSBuild>false</TypeScriptEnableIncrementalMSBuild>를 설정해 MSBuild가 실행될 때마다 TypeScript 컴파일러가 호출되도록 하세요.

더 알아보기 (Learn more)