Hey! :wave: I was just wondering what was the rea...
# javascript
n
Hey! 👋 I was just wondering what was the reason for the IR compiler not to export everything, only things marked with
@JsExport
. There must be a reason, right? When I say everything I mean everything used. Just as it is exported to JS but with name mangling. Thanks! C.C: @Arkadii Ivanov
a
Hey. The reason is pretty simple - size. With the model where everything could be used from JS - we can't eliminate "unused" declarations or minimize member names. Also, with this model, we can help users "prepare" exported declarations to be used from JS conveniently. In the non-IR compiler, you had "ugly" names for methods so they would not override.
a
Would it make sense (and is it even possible) to allow exporting types from libraries? E.g. if my JS project uses stdlib and some other libraries, I may need to export some types from those libraries even if the developer hasn't annotated them with JsExport. For a library developer, it's hard to predict all possible use cases. Since exporting everything is not good for the size, it would be nice to allow library users to export whatever they need from the library.
a
@Arkadii Ivanov, you are 100% right. And it's the biggest problem of the current model. We are looking for a declarative way to give this ability to "export" declarations placed in the module you don't own. We already discussed some ways, such as a defined list of fqNames from Gradle or defining a particular file that lists all your exported declarations in some intrinsic. However, we still don't know how to make it usable without extending Kotlin syntax.
Also, we are open to proposals, so, if somebody has some ideas around such API, we would be happy to discuss it.
a
Thanks! The reason why @Nacho Ruiz Martin tagged me here is because we've got a use case with my library - Decompose. Currently, none of the types are exported. The use case is to have all business and navigation logic shared via KMP, then export the module to JS and write a pure React UI for it. For instance, we can export the iOS framework to Xcode specifying that we also want to export
decompose
module. In this case we can access all types in Xcode and write SwiftUI code. It would be also nice to do the same with JS - export the
shared
Kotlin module and write React in pure JavaScript. As an idea, maybe provide some Gradle Kotlin DSL? Perhaps, something similar to
apiValidation
in https://github.com/Kotlin/binary-compatibility-validator. It could be something like:
Copy code
kotlin {
    js {
        exportedTypes.addAll(
            "com.arkivanov.decompose.router.stack.ChildStack",
            "com.arkivanov.decompose.value.Value",
            ...
        )
    }
}
🙏 1
gratitude thank you 1
t
External configuration (from Gradle) looks like single solution, which will cover known use cases
a
The Gradle DSL is what we tried to discuss, but there are a lot of issues with the solution, such as: • What should we do in case we change fqName? Error, warning, nothing? • What should we do with the clashed fqNames in different modules? Export both? And if it's overloaded function? • What name should we define for the clashed declarations (secondary constructor, overloaded functions,)? • What should we do in case when the declaration that should be exported is not exportable (annotation, value class, inner-class without its parent)? • The DSL could be used in every subproject, and it's hard to track which config "exports" the current declaration. • The renaming/moving functionality in IDEA will work.
👍 1
t
Typing answers... :)
loading 1
a
What about just exporting things transitively??? if I happen to annotate a single class/function, every public type used in that class/function should be transitively exported as well. Whats the down side to this solution? • Ofcourse, clashes (including Secondary constructors and overloaded functions) should error out with a good error message, providing the ability to rename symbols using gradle dsl • In case we change the fqName we error if there is a clash, otherwise just export everything
👍 1
e
I may need to export some types from those libraries even if the developer hasn't annotated them with JsExport
This is an ecosystem maturity issue. We should encourage everyone to cover all of the stable platforms. Exporting stuff you don't own sounds more like a workaround than an actual solution.
From an SDK/library perspective it should be fairly easy to understand what to
JsExport
. It's usually just the front facing API.
My personal opinion is that trying to pick what to export for the developer is a wasted effort. It looks cool on the surface as any other automated mechanism, but when targeting JS you want to be aware of everything you make available to the consumers.
I'll also add that the compiler warning for non-exportable types should become an error. It's happened multiple times I didn't notice it and I end up with
any
in the exported declarations.
a
This is an ecosystem maturity issue
Given the information above regarding the size, and as a library developer, I think I disagree. For example a library can be a multipurpose library, and only small part of it could be used in a project, and only a subset of that small part may be required by the consuming JS code. So exporting the whole public API of a library just in case looks indeed an overhead for most of the consuming projects. This essentially looks equivalent to "export everything by default", which has known downsides. On the other head, the proposed solution with automatic transitive export looks reasonable, I would probably lean towards it instead.
b
For external(lib) types @JsExport support on typealiases would be a pretty clean solution IMHO e.g. In my lib I could have
Copy code
@JsExport
typealias MyArray<T> = kotlin.Array<T>
Regarding last point of exporting everything by default, wouldn't this be ok when using esm and delegating actual treeshaking to webpack (or other equivalent js tooling) at the consuming application level (regardless if it's plain js or kjs app)
🤔 1
This would then be in line with plain js esm libs
a
Is there a tracking YT ticket for this feature, or should we create one?
b
I'm not aware of one, but would gladly donate my +1