KustomExport icon indicating copy to clipboard operation
KustomExport copied to clipboard

Export enum as String/Int

Open glureau opened this issue 4 years ago • 1 comments

Exporting enum to a class to be able to map additional properties and functions is increasing the JS bundle size. An alternative could be to export an enum as a string for example:

@KustomExport(exportMode = ExportMode.Enum.asString)
enum class Direction {
    NORTH, SOUTH, WEST, EAST
}

We could have a default mode to auto that could choose the mode asString or asInt if there is only one String/Int parameter, and choose the full wrapper when there is more than 1 constructor param or a method.

Full fledge wrapper
import sample._enum.Direction as CommonDirection // The annotated enum in commonMain

@JsExport
public class Direction internal constructor(
    internal val `value`: CommonDirection
) {
    public val name: String = value.name
}

public fun Direction.importDirection(): CommonDirection = value

public fun CommonDirection.exportDirection(): Direction = Direction(this)

@JsExport
public object Directions {
    public val NORTH: Direction = CommonDirection.NORTH.exportDirection()

    public val SOUTH: Direction = CommonDirection.SOUTH.exportDirection()

    public val WEST: Direction = CommonDirection.WEST.exportDirection()

    public val EAST: Direction = CommonDirection.EAST.exportDirection()
}

Export as String
import sample._enum.Direction as CommonDirection // The annotated enum in commonMain

typealias Direction = String

public fun Direction.importDirection(): CommonDirection = CommonDirection.valueOf(this)

public fun CommonDirection.exportDirection(): Direction = this.name

@JsExport
public const val Directions_NORTH: Direction = "NORTH"
@JsExport
public const val Directions_SOUTH: Direction = "SOUTH"
@JsExport
public const val Directions_WEST: Direction = "WEST"
@JsExport
public const val Directions_EAST: Direction = "EAST"

Bundle size (js) : 428 chars saved (no compressed) when exporting as strings (vs the full fledged export). A big part of the gain come from removing the object Directions and using (const) val instead, if we keep an object Dimensions the gain is only 14 chars. (So it's probably better to remove the object for the full fledged export, also const as no impact on bundle size.)

Limitations:

  • only available when there is no methods/properties (we may be able to use the 1st param instead of name when only one param is defined)
  • fun goTo(d: Direction) will be exported as goTo(direction: string); (as expected). It allows passing any string value, but a bad string will generate an IllegalStateException, possibly crashing the app.

Eventually there is an issue today with KSP/KotlinJsIr on multi-modules where external dependencies are not resolvable (WIP). With the current implementation, we expect a class not resolvable to be from another module, and it could be an issue with typealias resolution (not tested yet).

Also a little note about enums, Kotlin 1.6.20 should export enums without an additional layer... https://youtrack.jetbrains.com/issue/KT-37916

glureau avatar Nov 13 '21 10:11 glureau

Didn't have a lot of time to work on this topic, and 1.6.20 should come soon with a better enum support, so this topic is in standby for now.

glureau avatar Jan 26 '22 10:01 glureau