Anonymike
05/16/2025, 3:46 PMtoJs()
methods on classes that translate them to a JsObject external interface (a normal JS object, not a class). This is great in terms of managing model and logic in WASM, but obviously limited and a little costly on the frontend, though at this point it doesn't seem to be user noticeable. The limitations of the js() method, not being able to export classes, etc. has been a huge pain at every turn, so I'm hoping someone can shed some light on the balance they've found. We're going to try testing exporting common classes in the JS target and using them from the WASM target, but I fear that will be a complex mess to end up with friendlier code but much worse performance.
All ideas and experience are welcome and we'd love to exchange thoughts. We're still learning the costs and trade-offs of using WASM (as everyone is).turansky
05/17/2025, 9:15 PMtoJs
method?Anonymike
05/17/2025, 9:22 PMJSObject
and has the base functions for type handling etc. This is a test version of the code to prove the concept that will be more useful to you to drop in. Note the JsObjectClass
interface at the bottom that we'll use with our classes.
package io.codetactics.web.editor.model.js
@JsName("Object")
external class JsObject : JsAny {
operator fun get(key: JsString): JsAny?
operator fun set(key: JsString, value: JsAny?)
@JsName("hasOwnProperty")
fun has(key: JsString): Boolean
}
inline fun <T : JsAny> makeJsObject(init: T.() -> Unit): T = (JsObject().unsafeCast<T>()).apply(init)
fun Any.jsValueOf() = jsValueOf(this)
@Suppress("UNCHECKED_CAST")
fun jsValueOf(value: Any?): JsAny = when(value) {
is JsObjectClass -> value.toJsObject()
is String -> value.toJsString()
is Boolean -> value.toJsBoolean()
is Int -> value.toJsNumber()
is Long -> value.toJsBigInt()
is Double -> value.toJsNumber()
is List<*> -> value.map(::jsValueOf).toJsArray()
is Map<*, *> -> (value as Map<String, Any?>).entries.fold(JsObject()) { result, (key, value) ->
result.apply {
set(key.toJsString(), jsValueOf(value))
}
}
else -> error("Unsupported type: ${value?.let { it::class.simpleName }}")
}
interface JsObjectClass {
fun toJsObject() = JsObject()
}
Then, you can have a class that implements JsObjectClass
like so:
@Serializable
data class AnythingResponse(
var args: Map<String, String>,
var data: String,
var files: Map<String, String>,
var form: Map<String, String>,
var headers: Map<String, String>,
var json: Map<String, String>?,
var method: String,
var origin: String,
var url: String
) : JsObjectClass {
override fun toJsObject() = JsObject().apply {
set("args".toJsString(), args.jsValueOf())
set("data".toJsString(), data.jsValueOf())
set("files".toJsString(), files.jsValueOf())
set("form".toJsString(), form.jsValueOf())
set("headers".toJsString(), headers.jsValueOf())
set("json".toJsString(), json?.jsValueOf())
set("method".toJsString(), method.jsValueOf())
set("origin".toJsString(), origin.jsValueOf())
set("url".toJsString(), url.jsValueOf())
}
}
turansky
05/18/2025, 8:38 AMturansky
05/18/2025, 8:42 AMAnonymike
05/18/2025, 9:21 PM@JsExports
note the 's' annotation that applies to classes in both the js target and wasm target. It seems like a total mess and I've not seen any confirmation that it actually solves the problem, but like you said, you then end up with multiple copies of classes and you still have to make sure the WASM target knows that it can create those classes in JS.
And even if all that worked, you'd still be out of luck on your generic list haha.
For all the projects talking about the potential, the lack of translating even simple classes pretty much cripples WASM in a web client for us. I have no doubt jetbrains is working to make it happen, but its a problem of getting folks excited about it and posting creatively around the massive hole in functionality, while still trying to suggest its incredibly usable right now. I just feel that was a strategy mistake or perhaps its other bloggers and such looking for hype that made the mistake for jetbrains.turansky
05/19/2025, 1:24 PMAnonymike
05/19/2025, 7:45 PMAnonymike
05/19/2025, 7:50 PMAnonymike
05/19/2025, 7:54 PMturansky
05/20/2025, 6:06 PMturansky
05/20/2025, 6:08 PMJson
in current cases is workaround unfortunatelly, but probably it will work in your casesturansky
05/20/2025, 6:08 PMAnonymike
05/20/2025, 11:57 PMturansky
05/21/2025, 12:44 PMturansky
05/21/2025, 12:45 PMturansky
05/21/2025, 12:46 PMAnonymike
05/24/2025, 7:10 PMturansky
05/24/2025, 10:37 PMturansky
05/24/2025, 10:38 PMturansky
05/24/2025, 10:39 PMI feel it got a bit oversold by folks that were excited about itIs there links on videos with excited users? 🙂
Anonymike
05/24/2025, 11:04 PM