Kotlin でかんたんにインタラクティブなウェブアプリを書ける kweb とは結局なんなのか?
一般的なウェブアプリというのは、クライアントサイドを JS で書いて、サーバーサイドを kotlin 等の別の言語で書く、といったアプローチが一般的です。 このアプローチになるのは、基本的にクライアントサイドでは JavaScript で書く必要があるからです。近年では JavaScript に transpile したりwasm で動かしたりといろんなアプローチが生まれています。 kotlin 界隈でも kotlin/js を react で動かすなど、様々なアプローチが行われています。
一般的なこの方式では、クライアントサイドとサーバーサイドでのコードの共有が難しかったり、接続部分のコーディングが面倒だったりします。
一方 kweb では、クライアントサイドで動くコードを書くから大変なんだ!クライアントサイドで動くコードを書くのが大変なら全部サーバーサイドで動かせばいいじゃない!というアプローチをとっています。 ブラウザ上でのイベント発生時にサーバー側に通信を行って、サーバー側で処理します。そして、サーバー側で DOM を操作すれば、それがクライアントサイドに伝搬する感じになっています。 これらの通信を都度都度行うと高コストなので、websocket で通信を張りっぱなしにしています。 これはなんというか、まぁ通信コスト等も高いですし、富豪的プログラミング だなぁ、という感じですね! 富豪的ではありつつも、めちゃくちゃ簡単にインタラクティブなウェブページを宣言的に書くことができて楽しいです。僕のこのブログの編集画面も kweb で書かれていますが、以前の spring webmvc で書かれていたバージョンに比べると圧倒的にいじりやすくなっていますし、SPA をめちゃくちゃ簡単に実装できるようになっています。
たとえば、簡単な web chat システムを書く場合、以下のように書くだけ。client side と server side の通信プロセスは隠蔽されています。ObservableList に入れたものは、それを watch しているページを表示しているクライアントがあれば、それらすべてに websocket で描画の更新内容が伝搬されます。 実際にどういうふうに通信されてるかは chrome の inspector などで見るのが良いです。
import kweb.ButtonType
import kweb.InputElement
import kweb.InputType
import kweb.Kweb
import kweb.button
import kweb.form
import kweb.input
import kweb.li
import kweb.new
import kweb.state.KVar
import kweb.state.ObservableList
import kweb.state.renderEach
import kweb.ul
val list = ObservableList<String>()
fun main() {
Kweb(port = 16097) {
doc.body.new {
lateinit var inputElement: InputElement
lateinit var input: KVar<String>
form {
inputElement = input(type = InputType.text)
input = inputElement.value
button(type = ButtonType.submit)
.text("Tweet")
}.on(preventDefault = true).submit {
list.add(0, input.value)
inputElement.setValue("")
}
ul {
renderEach(list) { msg ->
li().text(msg)
}
}
}
}
}
一方で、サーバーサイドで state を持つことによる弊害もあります。 現行バージョンではサーバー側が再起動した場合の挙動がまだちょっと怪しいかもです。あと、Load balancer で sticky session にしないといけないですね。同じインスタンスに常にいかないといけないので。 あとドキュメントがちょっと荒削りだったりとか、まだまだ伸びしろがあるフレームワークだなーという感じ。
業務で使うにはまだちょっと早いかな、という感じはしつつ、考え方は面白いかなーと思うので最近これで遊んでいるというワケ。 コードベースも非常に小さいんで気軽にイジれるし。
Published: 2022-11-15(Tue) 23:40