さぁ君もKotlin/JSを始めよう【Kotlin/JS】

こんにちは。

先日Kotlin/JS を使って遊んでみたらすごくおもしろかったので布教したいと思います。

先人が残してくれた記事なども古くなっているため、今から始める人の手助けになるような記事を目指して書きます。

また、今回使用したプロジェクトはGitHub にて公開しています。

https://github.com/rokuosan/Sample-Kotlin-JS

# Kotlin/JS ってなに？

公式ドキュメントによるとKotlin/JSは以下のように説明されています。

> Kotlin/JS provides the ability to transpile your Kotlin code, the Kotlin standard library, and any compatible dependencies to JavaScript. 

> Kotlin/JSは、Kotlinのコード、Kotlinの標準ライブラリ、および互換性のある依存関係をJavaScriptにトランスパイルする機能を提供します。(DeepL翻訳)

つまり、KotlinをJavaScriptにしてくれるすごい技術のことです。

Kotlin.jsとかではないです。

# はじめよう

## 環境

今回、執筆にあたり使用した環境です。

|#|バージョン|
|:-|:-|
|Kotlin|1.6.10|
|IntelliJ IDEA Ultimate| 2021.3.2|
|JDK|Amazon Corretto JDK 11|
|Gradle|7.3.1|

ちなみに、IDEですがEclipseなどでも構いませんがKotlinの開発元はIntelliJ IDEAを開発しているJetBrainsなので、こちらを使ったほうがより多くの恩恵を受けれると思います。

## プロジェクトを作成する

プロジェクトの作成はIntelliJ IDEAからする方法とGradleからする方法がありますが、IntelliJ IDEAからの方が簡単です。

新規プロジェクトをKotlin からBrowser Application を選択して作成します

![2022-03-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447932/4b0d0e91-6f8f-5782-10d4-72f8070f609f.png)

次に何かを選ばされますが、そのままで問題ありません。

![2022-03-13 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447932/65adc4f0-2e4e-2200-a213-80fa56d8ce7e.png)

完了をクリックすればプロジェクトが完成します。

### 生成物

```kotlin:build.gradle.kts
plugins {
    kotlin("js") version "1.6.10"
}

group = "io.github.rokuosan"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    testImplementation(kotlin("test"))
}

kotlin {
    js(LEGACY) {
        binaries.executable()
        browser {
            commonWebpackConfig {
                cssSupport.enabled = true
            }
        }
    }
}
```
```kotlin:Simple.kt
fun main() {
    console.log("Hello, ${greet()}")
}

fun greet()="world"
```
```html:index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JS Client</title>
</head>
<body>
<script src="Sample-Kotlin-JS.js"></script>
<div id="root"></div>
</body>
</html>
```

## 動かしてみる

何も手を加えずに一度起動してみましょう。

右上にある実行構成を以下のどちらかであることを確認して実行ボタンを押してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447932/9a416ade-75d0-cc3e-d674-fde93b4b3ad5.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447932/16b6e689-5d17-780c-149a-676ea29a8c0a.png)


**初回起動はNPMなどを走らせるためにかなり時間がかかりますが、気長に待ちましょう。**

:::note warn
起動時にこのようなエラーが出ますが、無視してください。でなければ問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447932/c852f901-4883-adae-cca6-10fcb21a72ed.png)
:::

正常に起動するとログにこのような表示が見つかると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447932/0f11d4d5-f820-63b8-f39a-2c607cb0ad9b.png)

確認できたら、次はプログラムを書いてみます。

## 書いてみる

今回はサンプルとして、ボタンが出されたらアラートを出すものを書いてみます。

まずは、``index.html``のbodyをこのように書き換えてください

scriptタグのsrcは初期設定だとプロジェクト名と同じなので適宜書き換えてください。

```html:index.html
<body>
<div id="root">
    <button id="btn-1">
        押してみて
    </button>
    <button id="btn-2">
        押してみて2
    </button>
</div>
<script src="Sample-Kotlin-JS.js"></script>
</body>
```

次に、``Simple.kt``をを以下のように書き換えてください。

```kotlin:Simple.kt
import kotlinx.browser.document
import kotlinx.browser.window
import org.w3c.dom.HTMLButtonElement

fun main(){
    // 変数宣言
    val button1 = document.getElementById("btn-1") as HTMLButtonElement
    val button2 = document.getElementById("btn-2") as HTMLButtonElement

    // ボタン1のクリックイベントを定義
    button1.addEventListener("click", {
        window.alert("KotlinのDSLでアラートが出せたよ！")
    })

    // ボタン2のクリックイベントの内容をJSで記述した例(非推奨)
    button2.addEventListener("click", {
        js("alert(\"やろうと思えばKotlinからJSを無理やり呼び出すことも出来るよ！\")") as Unit
    })
}
```

変数宣言時に``as HTMLButtonElement``とすることでdocumentから取得した要素をボタン要素としてキャストしています。

イベントの定義は見ての通りです。

``js()``を使えば、文字列として記述したJSのソースコードをそのまま実行できます。まぁでも見てわかる通りクソみたいなコードになるので通常はお勧めしません。

これら二つを書き換えることが出来れば、実行して[localhost:8080](http://localhost:8080)に接続して確認してください。

![2022-03-13 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447932/c045d7e5-1cc4-b93e-78d8-bbf45abfc2e4.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447932/8271d5ed-db23-f5fc-b2e6-5eb667ffacba.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447932/15253534-e3d6-f09b-059a-bb165b0bc449.png)

適切に動作していることがわかると思います。

:::note info
もし動かない場合はJSが正しく読み込まれているか確認してください。
``index.html``にある``<script></script>``が``<body></body>``の最後にないと適切に動作しない場合があります。
:::

# Bootstrapを使ってみよう

Kotlin/JS でもBootstrap を使うことができます。

Bootstrap のCDNを利用してプロジェクトに埋め込みます。

[こちら](https://getbootstrap.jp/docs/5.0/getting-started/introduction/)の方法を参考に勧めます。

``index.html`` のheadにlinkタグを追加し、bodyの一番最後にscriptタグを追加してBootstrapのJSを読み込ませます。

もし出来ない場合はBootstrapのインストール方法に関する記事は星の数ほどあるのでｇｇれば解決するかと思います。

次に``Simple.kt``を編集します。

今回は先ほど作成したボタンをBootstrapを使ってボタンを押すとプログレスバーが進むアプリケーションを作ります。

```html:index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">

    <!--  Bootstrap CSS  -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    <title>JS Client</title>
</head>
<body>
<div id="root">
    <button id="btn-1" class="mx-2 my-2 btn btn-primary">
        押してみて
    </button>
    <h2 id="count">In progress: 0%</h2>
    <div class="progress">
        <div id="pb" class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
    </div>
</div>
<script src="Sample-Kotlin-JS.js"></script>
<!--  Bootstrap JS  -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</body>
</html>

```
```kotlin:Simple.kt
import kotlinx.browser.document
import org.w3c.dom.HTMLButtonElement
import org.w3c.dom.HTMLDivElement
import org.w3c.dom.HTMLHeadingElement

fun main(){
    val button1 = document.getElementById("btn-1") as HTMLButtonElement
    val field = document.getElementById("count") as HTMLHeadingElement
    val bar = document.getElementById("pb") as HTMLDivElement
    var count = 0

    button1.addEventListener("click", {
        // カウントを増やす
        if(count<100){
            count++
        }else{
            count=0
        }

        // 文字を変える
        "In progress: $count%".also {
            field.textContent=it
        }

        // 進捗を進める
        "$count%".also{
            bar.style.width=it
        }
    })
}
```
起動するとこのような画面になります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447932/d730afec-76b6-df07-3caf-2c57003ee529.png)

ボタンを押してみると...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447932/ed9ff50c-9226-f5d8-66a4-f1fb91d7de80.png)

値が変わり、プログレスバーが進みました🎉

# おわりに

Kotlin/JS、おもしろいでしょう？

思い立ったが吉日です。

これを読んだなら今すぐKotlin/JSを始めよう！

また、最後に作ったアプリケーションは[サンプル](https://rokuosan.github.io/Sample-Kotlin-JS/)から確認できます。

# 参考文献

https://kotlinlang.org/docs/js-overview.html#kotlin-js-frameworks

https://qiita.com/yt8492/items/250e4f7ac19fa8a66a74

https://getbootstrap.jp/