Как вызывать функции Kotlin/JS из обычного Javascript?

Я использую Kotlin для разработки небольшого программного обеспечения для 2D-моделирования, и я использую многоплатформенные проекты Kotlin, чтобы заставить его работать как на JVM, так и в браузере. Пока это работает хорошо.

Однако у меня возникает проблема, когда я хочу вызывать функции, определенные в Kotlin/JS, из обычного Javascript.

Чтобы мое приложение работало в браузере, я включаю большой JS-файл, который находится в папке «build/distributions» после запуска задачи Gradle «build». Когда мое приложение Kotlin/JS содержит функцию main(), она автоматически вызывается при открытии страницы HTML, ссылающейся на файл JS, и работает хорошо.

Но если я удаляю основную функцию и вместо нее создаю функцию start(), которая должна вызываться вручную (например, после нажатия кнопки), она не работает: она говорит, что функция start() не определена, хотя она объявлена ​​в коде Kotlin.

После открытия сгенерированного JS-файла кажется, что функции start() действительно нет. Похоже, все имена функций были минимизированы.

Я попытался добавить @JsName, но это ничего не изменило.

Так что я думаю, что я делаю что-то не так, но я действительно не знаю, что и как заставить это работать.

Примечание. Я использую Kotlin 1.3.70.

РЕДАКТИРОВАТЬ: Вот ядро ​​моего 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"
            }
        }
    }
}

person Fitz    schedule 12.02.2020    source источник


Ответы (1)


Вы должны вызвать функцию с именем модуля и полным именем:

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

В некоторых случаях (например, для поддержки перегрузок) компилятор Kotlin искажает имена сгенерированных функций и атрибутов в коде JavaScript. Чтобы управлять сгенерированными именами, вы можете использовать аннотацию  @JsName  

UPD: У вас есть два способа изменить имя модуля:

1) Если вы используете Gradle, вы можете добавить этот код в свой build.gradle

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

или в вашем build.gradle.kts

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

в этом случае вы должны использовать сгенерированный файл (app.js) в папке web (вы можете использовать другие имена папок и файлов).

2) Вы должны создать папку webpack.config.d и создать файл js с любым именем и содержимым, которое настраивает режим библиотеки для webpack

config.output = config.output || {} // just in case where config.output is undefined
config.output.library = "libraryName" // should be valid js variable name
person vanyochek    schedule 12.02.2020
comment
Я не уверен в имени модуля, который я должен вызвать. Мой модуль в Intellij IDEA называется «sim-view-js». Нужно ли мне переименовывать мой модуль Intellij или есть способ вызвать «sim-view-js.mypackage.foo()»? - person Fitz; 17.02.2020
comment
Вы должны называть его sim-view-js.mypackage.foo(), где mypackage — это имя вашего пакета. - person vanyochek; 17.02.2020
comment
sim-view-js не является допустимым именем Javascript. Я не могу это так назвать. - person Fitz; 17.02.2020
comment
Спасибо за ваш ответ, но я все еще сталкиваюсь с некоторыми проблемами. Подход (1) заключается в создании модуля с правильным именем, но я не могу легко включить его в представление HTML, поскольку модуль kotlin.js не может быть найден. С подходом (2) у меня четко отображается имя моего модуля, но имя функций не отображается (в пакете веб-пакета у меня нет строк статического экспорта). - person Fitz; 17.02.2020
comment
После новых тестов подход (2) работает. Просто мне нужна функция main(), даже если она пуста. Без этой функции остальные не выставлялись. Основная функция должна ссылаться на функции, которые я хочу предоставить. Поскольку я не хочу, чтобы эти функции вызывались, я заключил их в оператор if(false) {}. - person Fitz; 17.02.2020