9

If I have a JavaScript file called myfile.js as follows:

function myJsFunc() { return "Hello from JavaScript"; }

How can I import this file into a Kotlin/JS project and invoke myJsFunc() from Kotlin code?

funkybro
  • 8,432
  • 6
  • 39
  • 52
  • Maybe you should edit your question to be specific that it's for the Node.js target. For the browser target, this can be solved by adding further adjustments in the `webpack.config.d` folder as Joffrey pointed out. – Shreck Ye Jan 25 '22 at 11:41
  • Dukat has been removed from kotlin gradle plugin in recent versions as it was not reliable enough to be useful. The team is rethinking the approach before reintegrating it back. – Martynas Petuška Jul 04 '23 at 06:10

2 Answers2

3

Copied-over from slack discussion


First you need to declare an npm dependency in gradle

kotlin.sourceSets.named("jsMain") {
  dependencies {
    implementation(npm("package-name", "version"))
  }
}

Then you can either use ./gradlew generateExternals and pray that dukat works or write external declarations yourself.

package-name and version appears the same as it would in package.json, so all the protocols like file:xxx are supported as well.

You can also hack it with local TS sources, however I do not recommend it. If you still must stick with it, create a small npm module somewhere on your repo and use that via file:path/to/that/module version instead. I recommend generating absolute path to that module in gradle instead of trying to work out relative path from package.json that kotlin plugin generates

kotlin.sourceSets.named("jsMain") {
  dependencies {
    val pathToLocalNpmModule = rootProject.projectDir.resolve("js/my-module").canonicalPath
    implementation(npm("my-module", "file:$pathToLocalNpmModule"))
  }
}

Finally, for that particullar function, kotlin external declaration would look like this (assuming that you point your package.json#main field directly to that js file)

// Explicit export
export function myJsFunc() { return "Hello from JavaScript"; }

// Default export
export default myJsFunc
// Explicit export
@JsModule("my-module")
public external fun myJsFunc(): String

// Default export
@JsModule("my-module")
@JsName("default")
public external fun myJsFunc(): String

Now on the inverse, if you want to integrate your kotlin/js gradle module into local js/ts project, I recommend just using ./gradlew pack task provided by npm-publish gradle plugin (configures itself, just apply it) and use the bundle via file:xxx version protocol in your js/ts package.json.

  • Is there any documentation describing how to use Dukat with Gradle? I can't find anything. Searching `./gradlew generateExternals` doesn't give anything. It would be really nice to be able to generate Kotlin bindings with a gradle task. – mdornfe1 Jul 02 '23 at 17:54
-2

You will probably find some interesting information in the doc: Use JavaScript from Kotlin.

Essentially, you'll need to write external declarations manually to tell Kotlin about the functions and types that should be available in JS.

Making the file itself available depends on your build and how you deploy your code.

Joffrey
  • 32,348
  • 6
  • 68
  • 100
  • 2
    Hi, yes I have read this page many times already. Of `external` declarations, it says, tantalisingly, "When the compiler sees such a declaration, it assumes that the implementation for the corresponding class, function or property is provided externally (by the developer or via an npm dependency )" -- without explaining how to provide the implementation. – funkybro May 23 '21 at 15:05
  • @funkybro It will really depend on how you build your code and where the file comes from. For instance, how do you include the JavaScript file compiled from Kotlin into your application? Is it included in an HTML page? If so, and if your JS file is part of your sources, you can reference your JS file from the HTML. If your JS comes from an NPM dependency, you can use gradle's `dependencies` block with `npm()` helper to get it. – Joffrey May 23 '21 at 15:17
  • 3
    feels like the questions you're asking me are the questions I want the answer to :) If it helps, my project is ultimately going to run on Node.js rather than in the browser. No it does not come from an NPM dependency. Like I say in my question, it's a simple Javascript file which I want to include. You ask "How do you include the JavaScript file"? That's my question! Can it be loaded from the `resources` folder, for example? If not, how can I include it? – funkybro May 23 '21 at 15:22
  • @funkybro "you ask how do you include the JS file, that's my question" - Actually I asked how you include the JS file that is the build product of your Kotlin sources, not the JS file that you want to use as a dependency. I'm assuming you already have the Kotlin/JS project setup, with only Kotlin sources, and now you're trying to add a JS file as a dependency. That's why I ask questions about your setup of the Kotlin/JS project. – Joffrey May 23 '21 at 16:16
  • 1
    If it's going to run on nodejs, I'm assuming you intend to run the compiled Kotlin/JS file directly. I'm not well versed into runtime dependencies management in Node, but I think you may have to turn your JS file into a module and tweak the generated webpack config. Unfortunately I don't have much experience there, but you can most likely find help on the [Kotlin/JS public slack](https://kotlinlang.slack.com/archives/C0B8L3U69) – Joffrey May 23 '21 at 16:21
  • At the moment I'm simply using `./gradlew nodeRun` to run my project, and unsurprisingly it can't find my `external` function. I guess I need to put the JS file somewhere it can be found (where?) and include `@JSModule` or similar annotation to point to the name of the file and the function within the file (what exactly?) – funkybro May 23 '21 at 16:30