Kickstart Kotlin Web Assembly HTML DOM with Spring Boot

Submitted by Dickens A S on Wed, 04/29/2020 - 08:43

Easily create Kotlin Web Assembly project from these multiplatform boilerplate Gradle DSL

This code involves Custom JavaScript - to - Kotlin - to - JavaScript stub

GitHub https://github.com/dickensas/kotlin-gradle-templates/tree/master/sboot-wasm-dom

Kotlin Code

package wasm

import kotlinx.interop.wasm.dom.*
import kotlinx.wasm.jsinterop.*
import kotlinx.cinterop.*
import mymod.*

fun main() {

    //simple method call to a kotlin custom code
    mod.sayHello(" hello")
    
    //library method from "kotlinx.interop.wasm.dom"
    var div = document.getElementById("mydiv")
	
    //stub the div as object from "mymod"
    div = div.asDOMDiv
	
    //advanced property method call from "mymod"
    div.innerHTML = "Kotlin WebAssembly Accessing HTML DOM"
}

JavaScript Code

No need write the WASM loader, simply add this html

<script src="build/bin/wasm/releaseExecutable/sboot_wasm_dom.wasm.js" wasm="build/bin/wasm/releaseExecutable/sboot_wasm_dom.wasm"> </script>

To access DOM you need to write a kotlin+js stub and compile it to .klib

JavaScript Stub Code

konan.libraries.push ({
  sayHello: function(arena, obj, idPtr, idLen, resultArena) {
    var text1 = toUTF16String(idPtr, idLen);
    console.log("stub: " + text1);
  },
  getMyModule: function(resultArena) {
    if(!window['mymodule']) window['mymodule'] = {}
    return toArena(resultArena, window['mymodule']);
  },
  getInnerHTML: function(arena, obj) {
    var result = kotlinObject(arena, obj).innerHTML;
    return result;
  },
  setInnerHTML: function(arena, obj, idPtr, idLen, resultArena) {
    var text1 = toUTF16String(idPtr, idLen);
    kotlinObject(arena, obj).innerHTML = text1;
  }
})

Kotlin Stub Code

package mymod

import kotlinx.wasm.jsinterop.*

@SymbolName("sayHello")
external public fun sayHello(arena: Int, index: Int, idPtr: Int, idLen: Int, resultArena: Int): Unit

@SymbolName("getMyModule")
external public fun getMyModule(resultArena: Int): Int

@SymbolName("getInnerHTML")
external public fun getInnerHTML(arena: Int, index: Int, resultArena: Int): String

@SymbolName("setInnerHTML")
external public fun setInnerHTML(arena: Int, index: Int, idPtr: Int, idLen: Int, resultArena: Int): Unit

open class MyModule(arena: Int, index: Int): JsValue(arena, index) {
    constructor(jsValue: JsValue): this(jsValue.arena, jsValue.index)
    fun sayHello(id: String): Unit {
      sayHello(this.arena, this.index, stringPointer(id), stringLengthBytes(id), ArenaManager.currentArena)
    }
    companion object {
    }
}

val JsValue.asMyModule: MyModule
    get() {
      return MyModule(this.arena, this.index)
    }
  
val mod: MyModule
    get() {
      val wasmRetVal = getMyModule(ArenaManager.currentArena)
      return MyModule(ArenaManager.currentArena, wasmRetVal)
    }
    
open class DOMDiv(arena: Int, index: Int): JsValue(arena, index) {
    constructor(jsValue: JsValue): this(jsValue.arena, jsValue.index)
    var innerHTML: String
        get() {
          val wasmRetVal = getInnerHTML(this.arena, this.index, ArenaManager.currentArena)
          return wasmRetVal
        }
	
        set(value: String) {
           setInnerHTML(this.arena, this.index, stringPointer(value), stringLengthBytes(value), ArenaManager.currentArena)
        }
    companion object {
    }
}

val JsValue.asDOMDiv: DOMDiv
  get() {
    return DOMDiv(this.arena, this.index)
  }

Run gradle command

  gradle assemble

Run gradle command

  gradle run

Browse http://localhost:8080/index.html

Output 1: Check your browser console for text output "stub: hello" which will be the output from Web Assembly Code

Output 2: Check your browser the DIV tag updated using innerHTML - "Kotlin WebAssembly Accessing HTML DOM"

Spring Boot is used as a server to give MIME content-type as "application/wasm" , currently browsers does not recognize .wasm files with that MIME

 

Note:

The .klib file is auto generated in this project gradle task using kotlinc commandline, A typical example command line for generating klib in common is as below

kotlinc -include-binary t1.js -produce library -o t1.klib -target wasm32 t1.kt

Where t1.js which has JS stub and t1.kt has Kotlin code and corresponding Stub code

Add new comment