Skip to content

Kotlin/JS IRコンパイラ

Kotlin/JS IRコンパイラバックエンドは、Kotlin/JSにおける革新の主要な焦点であり、このテクノロジーの将来への道を切り開きます。

Kotlin/JS IRコンパイラバックエンドは、KotlinのソースコードからJavaScriptコードを直接生成するのではなく、新しいアプローチを活用します。KotlinのソースコードはまずKotlin中間表現 (IR)に変換され、その後JavaScriptにコンパイルされます。Kotlin/JSの場合、これにより積極的な最適化が可能になり、以前のコンパイラにあった課題点、例えば生成されるコードサイズ(デッドコードエリミネーションによるもの)やJavaScriptおよびTypeScriptエコシステムとの相互運用性といった点での改善を可能にします。

IRコンパイラバックエンドは、Kotlin 1.4.0以降、KotlinマルチプラットフォームGradleプラグインを通じて利用可能です。プロジェクトで有効にするには、Gradleビルドスクリプトのjs関数にコンパイラタイプを渡します。

groovy
kotlin {
    js(IR) { // or: LEGACY, BOTH
        // ...
        binaries.executable() // not applicable to BOTH, see details below
    }
}
  • IR はKotlin/JS用の新しいIRコンパイラバックエンドを使用します。
  • LEGACY は古いコンパイラバックエンドを使用します。
  • BOTH は、プロジェクトを新しいIRコンパイラとデフォルトのコンパイラバックエンドの両方でコンパイルします。このモードは両方のバックエンドと互換性のあるライブラリを作成する場合に使用します。

古いコンパイラバックエンドはKotlin 1.8.0以降非推奨となりました。Kotlin 1.9.0以降では、LEGACYまたはBOTHのコンパイラタイプを使用するとエラーが発生します。

コンパイラタイプは、gradle.propertiesファイルでkotlin.js.compiler=irというキーで設定することもできます。ただし、この動作はbuild.gradle(.kts)内の設定によって上書きされます。

トップレベルプロパティの遅延初期化

アプリケーションの起動パフォーマンスを向上させるため、Kotlin/JS IRコンパイラはトップレベルプロパティを遅延初期化します。これにより、アプリケーションはコード内で使用されるすべてのトップレベルプロパティを初期化することなくロードされます。起動時に必要なものだけが初期化され、他のプロパティは、それらを使用するコードが実際に実行されるときに後から値を受け取ります。

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

何らかの理由でプロパティを即時に(アプリケーション起動時に)初期化する必要がある場合は、@EagerInitializationアノテーションでマークしてください。

開発バイナリのインクリメンタルコンパイル

JS IRコンパイラは、開発プロセスを高速化する_開発バイナリのインクリメンタルコンパイルモード_を提供します。このモードでは、コンパイラはcompileDevelopmentExecutableKotlinJs Gradleタスクの結果をモジュールレベルでキャッシュします。これにより、変更されていないソースファイルに対してキャッシュされたコンパイル結果が後続のコンパイルで再利用され、特に小さな変更の場合にコンパイルが高速化されます。

インクリメンタルコンパイルはデフォルトで有効になっています。開発バイナリのインクリメンタルコンパイルを無効にするには、プロジェクトのgradle.propertiesまたはlocal.propertiesに次の行を追加します。

none
kotlin.incremental.js.ir=false // true by default

インクリメンタルコンパイルモードでのクリーンビルドは、キャッシュを作成して投入する必要があるため、通常は遅くなります。

出力モード

JS IRコンパイラがプロジェクトで.jsファイルをどのように出力するかを選択できます。

  • モジュールごと。デフォルトでは、JSコンパイラはコンパイル結果としてプロジェクトの各モジュールに対して個別の.jsファイルを出力します。

  • プロジェクト全体。プロジェクト全体を単一の.jsファイルにコンパイルするには、gradle.propertiesに次の行を追加します。

    none
    kotlin.js.ir.output.granularity=whole-program // 'per-module' is the default
  • ファイルごと。より細かな出力として、Kotlinファイルごとに1つ(または、ファイルにエクスポートされた宣言が含まれる場合は2つ)のJavaScriptファイルを生成するように設定できます。ファイルごとのコンパイルモードを有効にするには:

    1. ECMAScriptモジュールをサポートするために、ビルドファイルにuseEsModules()関数を追加します。

      kotlin
      // build.gradle.kts
      kotlin {
          js(IR) {
              useEsModules() // Enables ES2015 modules
              browser()
          }
      }

      あるいは、プロジェクトでES2015機能をサポートするためにes2015 コンパイルターゲットを使用することもできます。

    2. -Xir-per-fileコンパイラオプションを適用するか、gradle.propertiesファイルを更新します。

      none
      # gradle.properties
      kotlin.js.ir.output.granularity=per-file // 'per-module' is the default

プロダクションにおけるメンバー名のミニファイ化

Kotlin/JS IRコンパイラは、Kotlinのクラスと関数の関係に関する内部情報を使用して、関数、プロパティ、クラスの名前を短縮する、より効率的なミニファイ化を適用します。これにより、結果として生成されるバンドルされたアプリケーションのサイズが削減されます。

この種のミニファイ化は、Kotlin/JSアプリケーションをプロダクションモードでビルドする際に自動的に適用され、デフォルトで有効になっています。メンバー名のミニファイ化を無効にするには、-Xir-minimized-member-namesコンパイラオプションを使用します。

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

デッドコードエリミネーション

デッドコードエリミネーション (DCE) は、未使用のプロパティ、関数、クラスを削除することで、結果として生成されるJavaScriptコードのサイズを削減します。

未使用の宣言は、次のような場合に発生する可能性があります。

  • 関数がインライン化され、直接呼び出されない場合(一部のケースを除いて常に発生します)。
  • モジュールが共有ライブラリを使用している場合。DCEがないと、使用しないライブラリの一部も結果のバンドルに含まれます。 例えば、Kotlin標準ライブラリには、リスト、配列、文字シーケンスの操作、DOM用のアダプターなどの関数が含まれています。これらの機能すべてをJavaScriptファイルとして含めると約1.3MBが必要になります。「Hello, world」のような単純なアプリケーションでは、コンソールルーチンのみが必要であり、ファイル全体でもわずか数キロバイトで済みます。

Kotlin/JSコンパイラでは、DCEは自動的に処理されます。

  • DCEは、以下のGradleタスクに対応する_development_バンドルタスクでは無効化されます。

    • jsBrowserDevelopmentRun
    • jsBrowserDevelopmentWebpack
    • jsNodeDevelopmentRun
    • compileDevelopmentExecutableKotlinJs
    • compileDevelopmentLibraryKotlinJs
    • 名前に"development"を含むその他のGradleタスク
  • _production_バンドルをビルドすると、DCEが有効になります。これは以下のGradleタスクに対応します。

    • jsBrowserProductionRun
    • jsBrowserProductionWebpack
    • compileProductionExecutableKotlinJs
    • compileProductionLibraryKotlinJs
    • 名前に"production"を含むその他のGradleタスク

@JsExportアノテーションを使用すると、DCEがルートとして扱う宣言を指定できます。

プレビュー: TypeScript宣言ファイル (d.ts) の生成

TypeScript宣言ファイル (d.ts) の生成は実験的です。これはいつでも廃止または変更される可能性があります。 オプトインが必要であり(詳細は下記参照)、評価目的でのみ使用してください。YouTrackでフィードバックをいただけると幸いです。

Kotlin/JS IRコンパイラは、KotlinコードからTypeScript定義を生成できます。これらの定義は、ハイブリッドアプリで作業する際にJavaScriptツールやIDEが自動補完を提供し、静的アナライザーをサポートし、JavaScriptおよびTypeScriptプロジェクトにKotlinコードを含めることを容易にするために使用できます。

プロジェクトが実行可能ファイル (binaries.executable()) を生成する場合、Kotlin/JS IRコンパイラは@JsExportでマークされたすべてのトップレベル宣言を収集し、自動的に.d.tsファイルにTypeScript定義を生成します。

TypeScript定義を生成したい場合は、Gradleビルドファイルで明示的に設定する必要があります。jsセクションbuild.gradle.ktsファイルにgenerateTypeScriptDefinitions()を追加します。例:

kotlin
kotlin {
    js {
        binaries.executable()
        browser {
        }
        generateTypeScriptDefinitions()
    }
}

定義は、対応するwebpack化されていないJavaScriptコードとともにbuild/js/packages/<package_name>/kotlinにあります。

IRコンパイラの現在の制限事項

新しいIRコンパイラバックエンドの大きな変更点は、デフォルトのバックエンドとのバイナリ互換性がないことです。新しいIRコンパイラで作成されたライブラリはklib形式を使用するため、デフォルトのバックエンドからは使用できません。一方、古いコンパイラで作成されたライブラリはjsファイルを含むjarであり、IRバックエンドからは使用できません。

プロジェクトでIRコンパイラバックエンドを使用したい場合は、すべてのKotlin依存関係をこの新しいバックエンドをサポートするバージョンに更新する必要があります。Kotlin/JSをターゲットとするKotlin 1.4以降のJetBrainsから公開されているライブラリには、新しいIRコンパイラバックエンドで使用するために必要なすべてのアーティファクトがすでに含まれています。

ライブラリ開発者の方で、現在のコンパイラバックエンドと新しいIRコンパイラバックエンドの両方との互換性を提供したい場合は、さらにIRコンパイラ用のライブラリの作成に関するセクションを確認してください。

IRコンパイラバックエンドには、デフォルトのバックエンドと比較していくつかの相違点もあります。新しいバックエンドを試す際には、これらの潜在的な落とし穴に注意することが重要です。

  • デフォルトのバックエンドの特定の特性に依存する一部のライブラリ、例えばkotlin-wrappersは、いくつかの問題を示す可能性があります。YouTrackで調査と進捗を追うことができます。
  • IRバックエンドは、デフォルトではKotlinの宣言をJavaScriptから利用できるようにしません。Kotlinの宣言をJavaScriptから可視にするには、@JsExportアノテーションを付ける必要があります

既存プロジェクトをIRコンパイラに移行する

2つのKotlin/JSコンパイラ間には大きな違いがあるため、既存のKotlin/JSコードをIRコンパイラで動作させるには、いくつかの調整が必要になる場合があります。既存のKotlin/JSプロジェクトをIRコンパイラに移行する方法については、Kotlin/JS IRコンパイラ移行ガイドで確認してください。

後方互換性を持つIRコンパイラ用ライブラリの作成

既存のコンパイラバックエンドと新しいIRコンパイラバックエンドの両方との互換性を提供したいライブラリメンテナーの場合、両方のバックエンド用のアーティファクトを作成できるコンパイラ選択の設定が利用可能です。これにより、既存のユーザーとの互換性を維持しつつ、次世代のKotlinコンパイラをサポートすることができます。このいわゆるbothモードは、gradle.propertiesファイルでkotlin.js.compiler=both設定を使用するか、build.gradle(.kts)ファイル内のjsブロック内でプロジェクト固有のオプションの1つとして設定できます。

groovy
kotlin {
    js(BOTH) {
        // ...
    }
}

bothモードの場合、ソースからライブラリをビルドする際にIRコンパイラバックエンドとデフォルトのコンパイラバックエンドの両方が使用されます(そのため、この名前が付けられています)。これは、Kotlin IRを含むklibファイルと、デフォルトコンパイラ用のjarファイルの両方が生成されることを意味します。同じMaven座標で公開される場合、Gradleはユースケースに応じて適切なアーティファクト(古いコンパイラの場合はjs、新しいコンパイラの場合はklib)を自動的に選択します。これにより、両方のコンパイラバックエンドを使用するプロジェクト向けにライブラリをコンパイルおよび公開することができます。