ImpY
ImpY

Reputation: 23

Kotlin/JS unexpected behaviour by uncaught reference error

I'm try to call Kotlin functions by a JS from a HTML-Document. I set up the project with IntelliJ Idea like this so it's the

step 1

step 2

build.gradle.kts is configured like this:

plugins {
    kotlin("js") version "1.4.10"
}
group = "me.sample"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
    jcenter()
    maven {
        url = uri("https://dl.bintray.com/kotlin/kotlinx")
    }
}
dependencies {
    testImplementation(kotlin("test-js"))
    implementation("org.jetbrains.kotlinx:kotlinx-html-js:0.7.2")
}
kotlin {
    js {
        browser {
            binaries.executable()
            webpackTask {
                cssSupport.enabled = true
                output.libraryTarget = "commonjs"
            }
            runTask {
                cssSupport.enabled = true
            }
            testTask {
                useKarma {
                    useChromeHeadless()
                    webpackConfig.cssSupport.enabled = true
                }
            }
        }
        useCommonJs()
    }
}

The Kotlin file looks like this:

import kotlinx.browser.window

fun main() {
    window.onload = {

    }
}

fun test0() {
    console.log("test0")
}

@JsName("test1")
fun test1() {
    console.log("test1")
}

class TestClass {
    fun test0() {
        console.log("test0")
    }

    @JsName("test1")
    fun test1() {
        console.log("test1")
    }
}

The HTML document looks like this:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JS Client</title>
</head>
<body>
<script src="sample.js"></script>
<script>
    function callTest00() {
        test0()
    }
    function callTest01() {
        sample.test0()
    }
    function callTest10() {
        test1()
    }
    function callTest11() {
        sample.test1()
    }
    function callTestClass00() {
        new TestClass().test0()
    }
    function callTestClass01() {
        new sample.TestClass().test0()
    }
    function callTestClass10() {
        new TestClass().test1()
    }
    function callTestClass11() {
        new sample.TestClass().test1()
    }
</script>
<div id="root">
    <button onclick="callTest00()">00</button>
    <button onclick="callTest01()">01</button>
    <button onclick="callTest10()">10</button>
    <button onclick="callTest11()">11</button>
    <button onclick="callTestClass00()">TC00</button>
    <button onclick="callTestClass01()">TC01</button>
    <button onclick="callTestClass10()">TC10</button>
    <button onclick="callTestClass11()">TC11</button>
</div>
</body>
</html>

running the project as ProductionRun each button click in the HTML ends in:

Uncaught ReferenceError: test1 is not defined
    at callTest10 ((index):23)
    at HTMLButtonElement.onclick ((index):40)

Uncaught ReferenceError: TestClass is not defined
    at sample.callTestClass00 ((index):23)
    at HTMLButtonElement.onclick ((index):40)


...

also this warning appears:

client:135 asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets: 
  sample.js (262 KiB)

running the project as DevelopmentRun button clicks works fine for function with sample.Test..()

So my questions are:

  1. what and where do I need to adjust the project that the button clicks also work on ProductionRun
  2. what can I do against the asset size limit warning?
  3. where can I find the generated sample.js file?

Upvotes: 0

Views: 558

Answers (1)

vanyochek
vanyochek

Reputation: 905

The first and the second issue are fixed in IR backend

kotlin {
    js(IR) {
          //....
    }
}

In the Kotlin file, you have to add @JsExport annotation

@file:JsExport

import kotlinx.browser.window

fun main() {
    window.onload = {

    }
}

fun test0() {
    console.log("test0")
}
...

To call a Kotlin function from JS you have to use the module name.

    function callTest00() {
        sample.test0()
    }
    function callTest01() {
        sample.test0()
    }
    function callTest10() {
        sample.test1()
    }
    function callTest11() {
        sample.test1()
    }
    function callTestClass00() {
        new sample.TestClass().test0()
    }
    function callTestClass01() {
        new sample.TestClass().test0()
    }
    function callTestClass10() {
        new sample.TestClass().test1()
    }
    function callTestClass11() {
        new sample.TestClass().test1()
    }

The JS file is placed in sample/build/js/packages/sample/kotlin/sample.js The minified version in sample/build/distributions/sample.js (gradle build).

Upvotes: 1

Related Questions