In Kotlin/JS, the `org.w3c` and `kotlinx.browser` ...
# webassembly
r
In Kotlin/JS, the
org.w3c
and
kotlinx.browser
declarations have been extracted from stdlib to the separate artifact
kotlin-dom-api-compat
(see: https://youtrack.jetbrains.com/issue/KT-39330). But it's not the case with Kotlin/Wasm, which makes the declarations incompatible when using both Js and WasmJs targets (can't use them in
common
code). Can we expect similar artifact for Kotlin/Wasm? Any other workaround possible for this incompatibility? (there is already an issue based on my earlier report - https://youtrack.jetbrains.com/issue/KT-62398, with compose 1.6.0-alpha01 everything seems to work fine in common code except DOM declarations)
s
We will move them out of stdlib in Wasm at some point. But we have not yet figured out how to address this incompatibility without breaking changes in K/JS lib (as it uses types, like
dynamic
). If you are only using them “privately” without exposing types in your lib API, you could copy some of these to your codebase / separate library.
r
Unfortunately I can't because some types are exposed in the API
s
I would recommend to migrate away from using this APIs in shared Wasm + JS code, if possible. Wasm part will likely get a facelift with breaking changes in the future. They are not ready to be used in common library code, but, apparently, current multiplatform compiler allows it. You will probably have issues when compiling with K2, as they are not declared as proper
expect
-
actual
in stdlib.
r
So this is what I did. I've taken all dom/org.w3c.* sources from kotlin/wasm and put all of them into the common source set of my project with a different package name (MIT licence so it should be legal!). I've spend the whole day deleting internals, fixing errors and providing expect/actuals to make it compile for both JS and Wasm. Then I've made some changes to my project to use my own DOM declarations instead of stdlib. It works! My project is now fully usable in common source set. Even though my declarations are a bit imperfect (default
definedExternally
arguments can't be used in the common source set) all (~1300) tests are green and example projects are working fine. Does this sounds crazy enough to be good solution? 🙂
🔥 2
a
I'm trying to use
JSON.stringify
on wasm. Since it's not available in stdlib yet, I defined it as external. But it always returns null. Is there anything that I'm missing? Here is the code I'm running: https://pl.kotl.in/Q8zwEFraU.
Copy code
fun main() {
    val some = Some(value = 3)
    val ref = some.toJsReference()
    val s = JSON.stringify(ref)
    println(s)
}

data class Some(val value: Int)

public external object JSON {
    public fun stringify(o: JsAny?): String?
}
👀 1
r
I think the problem is
toJsReference()
the same JSON external object works fine for me
a
I tried
some as JsAny
but the result was the same - returns null.
How can I properly pass Some data class there?
r
I think you can't just "convert" wasm object to JsAny (js object)
a
So, is there any way to stringify a Kotlin object?
r
I would use
kotlinx.serialization
a
Oh that's sad, I wanted to avoid a dependency for this.
Actually, I think it wouldn't help in my case, as in the classic
js
target I'm currently using
stringify
against Any type.
r
I think with JS it will work with legacy backend, but with IR it won't work correctly (you will get mangled names).
a
Yes, but for my use case that worked.
I will try to avoid stringify if that's not working in WASM.
Oh, sorry! I just realised that I posted my message in a thread rather than in a new thread. Terrible Slack UX.
s
I can confirm, you can’t get automatic JS representation of Kotlin objects yet. JsReference is a low-level primitive for holding on to Kotlin objects and sending them back to Kotlin, you can’t do much with them in JS. But use case noted. I’m thinking of adding an annotation
@JsCopy
(name TBD) that you would put on data classes. These annotated types would then be allowed in external functions and data will be copied to a new plain JS object (and back) when crossing the
external
boundary. Would that help?
a
Thanks for the confirmation! May I use this thread for another related question? I assume we also can't use the Web History APIs? E.g.
kotlinx.browser.window.history.pushState(data = SomeKotlinData(), ...)
and then read the state via
val state = kotlinx.browser.window.history.state
and cast to the original
SomeKotlinData
. Or
toJsReference
should work in this case?
s
Oh, I got your question wrong. Yes, if you have an API that takes JsAny and gives you back the same reference, then you can use JsReference there.
a
I think it serialises the object under the hood. Kotlin Playground gives
Unhandled JavaScript exception: Failed to execute 'replaceState' on 'History': [object Object] could not be cloned.
But I haven't tried it yet in a real browser.
Yeah, not working in the Browser either.