🐣

Kotlin/Wasm(+React)でHello, World!してみる

2023/11/13に公開

寒くなってきましたね。筑波大学情報メディア創成学類3年のちゅるりです。Zenn は初投稿となります、よろしくおねがいします〜〜〜!

10月31日にリリースされた Chrome 119 で、WebAssembly GC(Garbage Collection)がついに正式機能になった[1]のを記念して、Kotlin/Wasm で Hello, World! してみたので、そのチュートリアルを残しておこうと思います。

Kotlin/Wasmとは

今まで、 Kotlin は主に Android アプリの開発言語として利用されてきました。しかし近年、JetBrains は Kotlin のマルチプラットフォーム言語戦略として、Kotlin/JVM を皮切りに、Kotlin/JS、Kotlin/Native といった様々なコンパイル・ターゲットを提供してきました。その一つとして Kotlin/Wasm があります。Kotlin/Wasm は、その名前からも類推されるように、Wasm(WebAssembly)を対象としたコンパイル・ターゲットです。Kotlin 1.9.20 にて Kotlin/Wasm のビルド済みの Wasm バイナリのサイズが、初期バージョンのときから10分の1となる[2]など、最近は活発に開発が進んでいるようです。
また、Chrome 119 で Wasm GC が正式機能として実装されたことにより、高級言語による Wasm 開発への門戸が開かれました。今までは、C++ や Rust、Go のような、主に低レイヤの実装でよく使われる言語によるWasm 開発が主流でした。従って、こういった言語には馴染みのない Web エンジニアの方々も多く(自分もそうでした)Wasm 開発の敷居は高いままでした。Wasm GC の実装により、Kotlin をはじめとして今後はより多くの言語で Wasm 開発が可能となることでしょう。

チュートリアル

今回は、Kotlin/Wasm で Hello, World! と出力するだけの Node.js ライブラリを作り、それを React アプリから読み込むという方法で Kotlin/Wasm を体験していきたいと思います。

環境

  • IntelliJ IDEA Ultimate 2023.1.2
  • (WebStorm 2023.1.2)
  • Google Chrome 119.x
  • Node.js v18.15.0
    WebStorm は無くても問題ありませんが、Kotlin を使用する都合で、IntelliJ はあるといいと思います。インストールは済ませておいてください。

下準備

Wasm GCの有効化

Chrome 119 で Wasm GC が正式機能になったとはいえ、GC フラグの有効化が必要なようです。

  1. chrome://flags を開く
  2. gc と検索し、WebAssembly Garbage CollectionEnabled にする
  3. Google Chrome を再起動する

Wasmライブラリを作る

見本のプロジェクトを GitHub に用意したので適宜参考にしてください!

プロジェクトの作成

次のようにプロパティを設定し、CREATE をクリックしてください。

  • Name: kotlin-wasm-example
  • Language: kotlin
  • Build System: Gradle
  • Gradle DSL: Kotlin

build.gradle.ktsの設定

GitHubのkotlin-wasm-examplebuild.gradle.kts の内容を自分の build.gradle.kts にコピペします。エラーが出るかと思いますが、一度無視して構いません。

src/mainのリネーム

src/main ディレクトリを src/wasmJsMain とリネームします。

プロジェクトのリロード

build.gradle.kts を変更したので、プロジェクト全体をリロードする必要があります。右側の Gradle タブを開いて、Gradle という文字列直下のリロードボタン(丸い矢印)をクリックしてください。リロードにはしばらく時間がかかります。リロードが終了すると、build.gradle.kts のエラーが消えているかと思います。

Main.ktの作成

いよいよ実行対象となる Kotlin プログラムを作成します。src/wasmJsMain/kotlin 配下に Main.kt という名前で Kotlin ファイルを作成してください。作成したのち、次のプログラムを書き込みます。

@JsExport アノテーションを使用することで、Kotlin 関数を JavaScript 側にエクスポートすることができるようです[3]。また、main 関数はこの Wasm モジュールが読み込まれた際に実行されるようです。

fun main() {
    println("Loaded!")
}

@JsExport
fun hello() {
    println("Hello, World!")
}

プロジェクトのビルド

右側の Gradle タブの kotlin node/wasmJsNodeRun を実行し、Wasm へのコンパイルとNode.js ライブラリの生成を行います。しばらくの時間の後、左側のファイルツリーに build ディレクトリが生成されると思います。

npmパッケージをリンクする

続いてターミナルを開き、生成された Node.js ライブラリをnpmを通してリンクします(npm link についてはこちら

$ cd build/js
$ npm link

これで、Kotlin/Wasm の Node.js ライブラリの作成は終わりです。めちゃくちゃ手軽ですね。

Kotlin/Wasmを使用するReactアプリを作る

Reactアプリを作成する

僕は JetBrains 系 IDE をよく使用するので WebStorm を使用します。適当な名前でプロジェクトを作成してください。

webpackDevServer.config.jsを設定する

本来はこの手順を飛ばしてもよいはずですが、現状このまま進むと *.wasm ファイルを fetch したときに Invalid MIMEtype エラーが発生してしまってうまく動かないので、これを抑制します。

node_modules/react_scripts/config/webpackDevServer.config.js を開き、onBeforeSetupMiddleware(devServer) 関数内に次のコードを追加してください。

devServer.app.get('*.wasm', function (req, res, next) {
    var options = {
        root: `${__dirname}/../../kotlin-wasm-example/packages/kotlin-wasm-example-wasm-js/kotlin`,
        dotfiles: 'deny',
        headers: {
            'Content-Type': 'application/wasm'
        }
    };
    res.sendFile(req.url, options, function (err) {
        if (err) {
            next(err);
        }
    });
});

以上の抑制方法は開発環境で動かすこと前提であり、特に node_modules を改変しているという点で本来はあまりすべきではありません。しかし、今回は Kotlin/Wasm をいち早く体験するというために、このような処置を実行しています。ほかの対応方法を検討する場合、application/wasm MIMEtype問題を解決しつつ開発サーバを建てる方法等の記事が参考になるかと思います。

作成したパッケージをリンクする

プロジェクトのルートディレクトリで次のコマンドを実行し、先程作成したNode.jsライブラリをリンクします。

$ npm link kotlin-wasm-example

App.jsxでWasmの読み込みを行う

App.jsxに次のコードを挿入してください。今回はこれだけで大丈夫です。

// 挿入
import wasmModule from 'kotlin-wasm-example/packages/kotlin-wasm-example-wasm-js/kotlin/kotlin-wasm-example-wasm-js.mjs';
import {useEffect} from "react";

function App() {
  // 挿入
  useEffect(() => {
    wasmModule.hello()
  }, []);
  // 挿入ここまで
  
  return // ...
}

実行する

npm run start を実行し、開発サーバを立ててブラウザでアクセスしてみてください。うまく行っていれば、コンソールに Hello, World! が表示されているかと思います...おめでとうございます!これで Hello, World が完了しました!
!

さいごに

今回は Kotlin/Wasm で Hello, World! をする方法をご紹介しました。Kotlin で Wasm を開発できるようになったのはとてもおもしろく、Web 開発の幅がまた広がったように感じます。僕自身も今回はじめて Kotlin/Wasm に触ってみたので、今後も得られた知見などを随時まとめていきたいと思います。最後までお読みいただきありがとうございました。

脚注
  1. WebAssemblyのガベージコレクションが正式機能に、最新版のChrome 119で。Firefoxも今月リリースのFirefox 120で正式機能になる見通し ↩︎

  2. Kotlin by JetBrains - X ↩︎

  3. Interoperability with JavaScript / Use Kotlin code from JavaScript / @JsExport annotation ↩︎

Discussion