Kotlin JavaScript を試す！

# 更新履歴

* 2019.11.10 - コンパイル時に生成される `{module}.js` についての説明を一部修正しました。

# Kotlin JavaScript とは

KotlinをJVM上で実行できるよう、Javaのクラスファイルにコンパイルできることは有名ですが、JavaScriptへコンパイルすることもできます！現在はECMAScript5.1へコンパイルすることができるみたいですが、将来的にECMAScript2015へもコンパイルできるようになるみたいです。KotlinのJavaScriptコンパイラは以下の３つのことをしてくれます。

* ファイルサイズの最適化
* よみやすいJavaScriptへの変換
* モジュールシステムの利用
* 標準ライブラリの使用

注意してほしいのが使用しているJDKやJava等のすべてのコードがコンパイルされるわけではないというところです。例えばSpringFrameworkを使用しているKotlinのコードをコンパイルしても、SpringFrameworkはJavaScriptへコンパイルされないということだと思います。そのような非対応モジュールはコンパイル時に無視されます。

KotlinのJavaScriptコンパイルでは以下の状況で使用できます。

* クライアントサイド JavaScript
    * DOM要素の操作
    * WebGLの操作
* サーバーサイド JavaScript
    * Node.jsといったサーバーサイド技術使用

クライアントサイドではjQueryやReactといったライブラリを同時に使用することが可能です。これは非常に良いですね。このような場合は型情報をTypeScriptの型定義情報から入手するみたいです。TypeScriptの型定義情報はそのままKotlinでは使用できないので[dukat](https://github.com/kotlin/dukat)というツールを使用します。

Kotlinの開発・保守をしているJetBrainsではReactのツール開発・保守にも関わっているみたいで、[Create React Kotlin App](https://github.com/JetBrains/create-react-kotlin-app)をつかうことでReactのKotlin版を一瞬で作れるようになっています。ただ、このツールは記事執筆時点でEarly Preview版でした。

# Kotlin を JavaScript へ変換する

KotlinをJavaScriptへ変換すると２種類のファイルが生成されます。

* kotlin.js
    * ランタイムと標準ライブラリを含むファイル
* {module}.js
    * アプリケーションコードが含まれるファイル。アプリケーションコードは一つのファイルに集約され、`{module}`にはKotlinのモジュール名が使われる。

変換後のアウトプットファイルの中身の解説が、[公式ドキュメント](https://kotlinlang.org/docs/tutorials/javascript/kotlin-to-javascript/kotlin-to-javascript.html#examining-the-compilation-output)でされているので、興味のある方は読んでみると面白いと思います。時間があれば、どのように変換が行われているのか、詳しく見てみたいですね。

変換の方法はいかに上げる４つの方法があります。

* Gradle
* IntelliJ IDEA
* Maven
* Command Line

ここではIntelliJのプロジェクト作成によってGradleを指定し実際に変換してみたいと思います。作成時には`Kotlin/JS for Node.js`を指定しました。生成されたファイル、ディレクトリはこちら。

```
.
├── build.gradle
├── gradle
│   └── wrapper
├── gradle.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    ├── main
    └── test
```

build.gradleはこうなっています。プラグインでkotlinをJavaScriptへ変換できるようにしているみたいですね。依存ライブラリでも`stdlib-js`というものを使っています。

```
plugins {
    id 'org.jetbrains.kotlin.js' version '1.3.50'
}

group 'com.bookstore'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-js"
    testImplementation "org.jetbrains.kotlin:kotlin-test-js"
}

kotlin.target.nodejs { }
```

動作を確認したいので、`Hello, Javascript!`と出力するメイン関数を定義してみました。

``` kotlin:src/main/kotlin/ConcoleOutput.kt
fun main() {
    println("Hello, JavaScript!")
}
```

ここでビルドを実行すると、`build`ディレクトリにコンパイル結果が生成されます。どうやらアプリケーションのコードは`build/js/packages`に出力され、ランタイムと標準ライブラリのコードは`build/js/package-imported`に出力されるみたいです。

```
build/js/packages
├── example
│   ├── kotlin
│   │   ├── example
│   │   │   └── root-package.kjsm
│   │   ├── example.js
│   │   ├── example.js.map
│   │   └── example.meta.js
│   ├── package.json
│   └── package.json.hash
└── example-test
    ├── package.json
    └── package.json.hash
```

```
build/js/packages_imported
├── kotlin
│   └── 1.3.50
│       ├── kotlin.js
│       ├── kotlin.js.map
│       └── package.json
├── kotlin-test
│   └── 1.3.50
│       ├── kotlin-test.js
│       ├── kotlin-test.js.map
│       └── package.json
└── kotlin-test-nodejs-runner
    └── 1.3.50
        ├── kotlin-nodejs-source-map-support.js
        ├── kotlin-nodejs-source-map-support.js.map
        ├── kotlin-test-nodejs-runner.js
        ├── kotlin-test-nodejs-runner.js.map
        └── package.json
```

実際に呼び出してみました。

``` bash
> node -v
v12.13.0

> node build/js/packages/example/kotlin/example.js
Hello, JavaScript!
```

きちんとコンソール出力されています。このサンプルコードの他にも、クラスを定義してみたり試しましたが、KotlinのコードがきちんとJavaScriptになって実行できました。すばらしい！

# 次は...

KotlinのコードをJavaScriptへ変換するやり方がわかりました！次はライブラリを使うやり方や、KotlinからJavaScript、JavaScriptからKotlinを呼び出す方法等を試してみたいと思います。

# 参考

[Kotlin 公式リファレンス | Kotlin to JavaScript](https://kotlinlang.org/docs/tutorials/javascript/kotlin-to-javascript/kotlin-to-javascript.html)