1

I’ve been using Kotlin to develop a small 2D simulation software, and I’m using Kotlin multiplatform projects to make it run on both the JVM and in a browser. So far it works well.

However, I have a problem when I want to call functions defined in Kotlin/JS from regular Javascript.

To make my application work in the browser, I’m including the big JS file which is under the “build/distributions” folder after running the “build” Gradle task. When my Kotlin/JS application contains a main() function, this one is automatically being called when the HTML pag referencing the JS file is opened, and it works well.

But if I remove the main function and instead I create a start() function which is supposed to be called manually (after a click on a button, for instance), it does not work: it says the function start() is not defined even though it is declared in the Kotlin code.

After opening the generated JS file it seems that indeed there is no start() function. It looks like all the name of the functions have been minified.

I tried adding @JsName, but it didn’t change anything.

So I guess I’m doing something wrong, but I really don’t know what and how to make it work.

Note: I'm using Kotlin 1.3.70

EDIT: Here is the core of my build.gradle.kts:

plugins {
    kotlin("js") version "1.3.70-eap-184"
}


repositories {
    mavenLocal()
    mavenCentral()

    maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
}

dependencies {

}

kotlin {
    target {
        nodejs {

        }
        browser {
            webpackTask {
                mode = org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig.Mode.PRODUCTION
                bin = "$projectDir/node_modules/$bin"
            }
        }
    }
}

1 Answer 1

3

You should call the function with the module name and qualified name:

https://kotlinlang.org/docs/reference/js-to-kotlin-interop.html#package-structure

package my.qualified.packagename

fun foo() = "Hello"
alert(myModule.my.qualified.packagename.foo());

https://kotlinlang.org/docs/reference/js-to-kotlin-interop.html#jsname-annotation

In some cases (for example, to support overloads), Kotlin compiler mangles names of generated functions and attributes in JavaScript code. To control the generated names, you can use the  @JsName  annotation

UPD: You have two ways to change the module name:

1) If you use gradle you can add this code to your build.gradle

compileKotlinJs {
    kotlinOptions.outputFile = "${rootDir}/web/app.js" // should be valid js variable name
}

or in your build.gradle.kts

kotlin {
    target {
        compilations.all {
            kotlinOptions.outputFile = "${rootDir}/web/app.js"
        }
    }
}

in this case you should use generated file (app.js) in the web folder (you can use other folder and file names).

2) You should create folder webpack.config.d and create js file with any name, and content which configures library mode for webpack

config.output = config.output || {} // just in case where config.output is undefined
config.output.library = "libraryName" // should be valid js variable name
Sign up to request clarification or add additional context in comments.

6 Comments

I'm not sure of the module name I should call. My module in Intellij IDEA is called 'sim-view-js'. Do I have to rename my Intellij module or is there a way to call 'sim-view-js.mypackage.foo()'?
You should call it sim-view-js.mypackage.foo() where mypackage is the name of your package.
sim-view-js is not a valid Javascript name. I can't call it this way.
Thank you for your answer, but I'm still facing some issues. Approach (1) is generating a module with the right name, but I can not easily include it in a HTML view as "module kotlin.js cannot be found". With approach (2) I have the name of my module clearly exposed, but the name of the functions are not exposed (in the webpack bundle I've "no static exports found" lines).
After new tests, approach (2) is working. It's just that I need to have a main() function, even if empty. Without this function, the other ones were not exposed. The main function must refer to the functions I want to expose. As I don't want these functions to be called, I've wrapped them in a if(false) {} statement.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.