What's the reason for `@JsExport` on `initHook`? <...
# ktor
@Oleg Yukhnevich probably you know the answer.
o
https://youtrack.jetbrains.com/issue/KT-51626/Kotlin-JS-EagerInitialization-annotation-has-no-effect-on-unused-properties This is all I know 🙂 I've discovered it by accident. My guess: making it
@JsExport
makes it usable in an exported JS module, and so the initializer is called - otherwise, as it's not "exported" and it's not called anywhere it's just removed by DCE
@Artem Kobzar might know more about why it works like this
e
Would make sense, indeed. Asked as while experimenting with Ktor and the MCP SDK, I've noticed
initHook
in the generated
d.ts
. From my quick testing, it looks like
@EagerInitialization
now also works on unused properties.
âž• 1
image.png
o
From my quick testing, it looks like
@EagerInitialization
now also works on unused properties.
yes! it really works! I've checked on Kotlin 2.3.20 - works for both default and
es2015
JS target So, looks like it might have been fixed at some point
e
Yup! Nice. Maybe Artem knows whether there is a proper explanation to the fix, or if it's accidental. But definitely a test case for regression is worth adding.
b
Ah so we can drop
@JsExport
now? very nice
o
It works for CK - here is a PR for ktor - https://github.com/ktorio/ktor/pull/5580 🙂
gratitude thank you 3
e
Note that the consumer is important here. If Ktor removes it now, but a consumer uses a version of Kotlin that still has this bug, it will break. We need to check the initial version where it's fixed. Since Ktor uses 2.3.21 now (iirc) it should be at least 2.3.0.
âž• 2
Folks, something I had completely overlooked is minification. While the annotation seems to work as expected on unused properties now, it's only working in terms of outputted JS code. In the past the compiler didn't even output the initialization logic, while now it does. However, being that a unused variable isn't reachable anywhere, a bundler like Webpack or ESBuild will check for side effects and remove it in case none is found. So how do you "force" a side-effect? Something like this seems to work:
Copy code
@OptIn(ExperimentalStdlibApi::class)
@EagerInitialization
@JsName("example")
private val example = run {
    js("eval('void example')")
    return@run "value without side-effects"
}
Webpack will see
void example
and back off from removing it.
Btw, the
eval
is required because
js
literals are parsed and contribute to variable name uniqueness checks. If you use
js("void example")
the
example
variable will never exist.
interesting 1