Hi all, when building a Kotlin/JS or Kotlin/Wasm l...
# javascript
m
Hi all, when building a Kotlin/JS or Kotlin/Wasm library, if i have understood things correctly, we must choose between
browser()
and
nodeJs()
(?) My question is, is it possible to support both
browser()
and
nodeJs()
for example by creating two
js()
target (if it is possible) ? Will the library consumer encounter issues when including it with
browser()
while it only supports
nodeJs()
?
e
https://youtrack.jetbrains.com/issue/KT-47038 It's something that has been discussed for quite some time. The answer is you currently have to be careful and detect on which platform you're running, if you want to support both scenarios. Multiple targets are deprecated an error now, although the Kotlin team has been nice and has left us with a "backdoor" only for K/JS, until a proper solution is found. So yes, you can have multiple JS targets now, but it's not a long term thing imo.
The thing you have to remember is annotating a declaration (or a file) with
@JsModule
means eagerly loading it. You cannot import a Node.js module and expect the compiled code to work in the browser, even tho you're not even passing by that piece of code, because the script immediately requires that module. Also see https://youtrack.jetbrains.com/issue/KT-20679
As an example, this is how I dynamically import Node's
net
module to instantiate a new `Socket`:
Copy code
val netModule = jsRequire<NetModule>("node:net")
val socket = netModule.Socket.newInstance()
The typings are:
Copy code
@Suppress("PropertyName")
external interface NetModule {
  val Socket: SocketStatics
}

@Suppress("NOTHING_TO_INLINE", "UNUSED_VARIABLE", "UnsafeCastFromDynamic")
inline fun SocketStatics.newInstance(): Socket {
  val socket = this
  return js("new socket()")
}

@Suppress("NOTHING_TO_INLINE", "UNUSED_PARAMETER", "UnsafeCastFromDynamic")
inline fun <T : Any> jsRequire(name: String): T =
  js("require(name)")
And, if after seeing
js("require(name)")
, you're wondering "how's it gonna work if a consumer compiles to ESM?", the answer is it won't. Well, it will work in the latest Node.js version just because requiring ESM is now allowed, but generally speaking it will just break.
m
Thank you for your explanations and for sharing your example. Now that I'm aware that it is a long term issue that is not going to be addressed sooner, I think I'll go with
browser()
and do runtime checks to determine the environment and know which API is available until the issue is addressed. But yes, truly sad having so much cleanly distinct Apple targets but having to deal with runtime tricks for the single JS target. I was too far from the reality, thinking there's more browser/nodeJs application opportunities than watchOsArm32 HFP. In the meanwhile I do not know how trivial it is to create distinct Apple targets than web targets but I think priority needs to be reconsidered. I wasn't aware of that lazy loading API, thanks for sharing.
blob no problem 1
e
Btw, using
browser
or
nodeJs
with
binaries.library
has effectively no difference. Pick one or the other based on preference, the actual behavior difference comes with
binaries.executable
.
kodee loving 1