Kotlin/JS 컴파일러 기능

Kotlin/JS 컴파일러 기능

Kotlin/JS는 성능, 크기, 개발 속도를 최적화하기 위한 컴파일러 기능을 포함하고 있어요. 이는 Kotlin 코드를 JavaScript 코드로 생성하기 전에 중간 표현(IR)으로 변환하는 컴파일 프로세스를 통해 작동합니다.

출처: Kotlin/JS compiler features

본문

최상위 프로퍼티의 지연 초기화

더 나은 애플리케이션 시작 성능을 위해, Kotlin/JS 컴파일러는 최상위 프로퍼티를 지연해서(lazily) 초기화해요. 이렇게 하면 애플리케이션이 코드에 사용된 모든 최상위 프로퍼티를 초기화하지 않고도 로드됩니다. 시작 시 필요한 프로퍼티만 초기화하고, 나머지 프로퍼티는 실제로 사용하는 코드가 실행될 때 값을 받게 돼요.

val a = run {
    val result = // intensive computations
    println(result)
    result
} // value is computed upon the first usage

어떤 이유로 프로퍼티를 (애플리케이션 시작 시) 즉시 초기화해야 한다면, @EagerInitialization 애너테이션으로 표시하세요.

개발 바이너리의 증분 컴파일

Kotlin/JS 컴파일러는 개발 프로세스를 빠르게 해 주는 개발 바이너리용 증분 컴파일(incremental compilation) 모드를 제공해요. 이 모드에서 컴파일러는 compileDevelopmentExecutableKotlinJs Gradle 태스크의 결과를 모듈 수준에서 캐시합니다. 이후 컴파일에서 변경되지 않은 소스 파일에 대해 캐시된 컴파일 결과를 사용하므로, 특히 작은 변경이 있을 때 더 빨리 완료됩니다.

증분 컴파일은 기본적으로 활성화되어 있어요. 개발 바이너리의 증분 컴파일을 비활성화하려면 프로젝트의 gradle.properties 또는 local.properties에 다음 줄을 추가하세요:

kotlin.incremental.js.ir=false // 기본값은 true

증분 컴파일 모드의 클린 빌드(clean build)는 캐시를 만들고 채워야 하기 때문에 보통 더 느립니다.

프로덕션에서 멤버 이름 축소(Minification)

Kotlin/JS 컴파일러는 Kotlin 클래스와 함수의 관계에 대한 내부 정보를 사용해 더 효율적인 축소를 적용해, 함수·프로퍼티·클래스의 이름을 짧게 만듭니다. 이로써 결과적으로 번들된 애플리케이션의 크기가 줄어들어요.

이 유형의 축소는 프로덕션 모드에서 Kotlin/JS 애플리케이션을 빌드할 때 자동으로 적용되며, 기본적으로 활성화되어 있습니다. 멤버 이름 축소를 비활성화하려면 -Xir-minimized-member-names 컴파일러 옵션을 사용하세요:

kotlin {
    js {
        compilations.all {
            compileTaskProvider.configure {
                compilerOptions.freeCompilerArgs.add("-Xir-minimized-member-names=false")
            }
        }
    }
}

데드 코드 제거

데드 코드 제거(DCE, Dead Code Elimination)는 사용되지 않는 프로퍼티, 함수, 클래스를 제거해 결과 JavaScript 코드의 크기를 줄여요.

사용되지 않는 선언은 다음과 같은 경우에 생길 수 있습니다:

  • 함수가 인라인되어 직접 호출되지 않는 경우(몇 가지 경우를 제외하고 항상 발생)입니다.
  • 모듈이 공유 라이브러리를 사용하는 경우입니다. DCE가 없으면 사용하지 않는 라이브러리 부분도 결과 번들에 포함됩니다. 예를 들어 Kotlin 표준 라이브러리에는 리스트, 배열, 문자 시퀀스 조작 함수, DOM용 어댑터 등이 포함되는데, 이 모든 기능은 JavaScript 파일로 약 1.3MB가 필요해요. 단순한 "Hello, world" 애플리케이션은 콘솔 루틴만 필요하므로 전체 파일이 몇 KB에 불과합니다.

Kotlin/JS 컴파일러에서 DCE는 자동으로 처리돼요:

  • DCE는 다음 Gradle 태스크에 해당하는 개발 번들링 태스크에서 비활성화됩니다:

    • jsBrowserDevelopmentRun
    • jsBrowserDevelopmentWebpack
    • jsNodeDevelopmentRun
    • compileDevelopmentExecutableKotlinJs
    • compileDevelopmentLibraryKotlinJs
    • 이름에 "development"가 포함된 기타 Gradle 태스크
  • 다음 Gradle 태스크에 해당하는 프로덕션 번들을 빌드하면 DCE가 활성화됩니다:

    • jsBrowserProductionRun
    • jsBrowserProductionWebpack
    • compileProductionExecutableKotlinJs
    • compileProductionLibraryKotlinJs
    • 이름에 "production"이 포함된 기타 Gradle 태스크

@JsExport 애너테이션을 사용하면 DCE가 루트로 취급할 선언을 지정할 수 있어요.

더 알아보기