https://kotlinlang.org logo
#javascript
Title
# javascript
e

Edoardo Luppi

11/24/2023, 3:03 PM
Or even better. Having a series of JavaScript files, is there a better way to integrate them into a KJS module?
Would something like this work for you? Or are you integrating the other way around: local js to local kt?
e

Edoardo Luppi

11/24/2023, 7:06 PM
The other way around! Consuming local JS files from Kotlin
b

Big Chungus

11/24/2023, 7:07 PM
You should be able to just drop js files in resources dir and then just require them by path relative to resources root
💥 1
e.g. given src/jsMain/resources/subpath/file.js You can require it in kotlin via
Copy code
external fun require(module: String): dynamic

val jsModule = require("./subpath/file.js")
e

Edoardo Luppi

11/24/2023, 7:11 PM
Damn, that's pretty neat. I suppose that if the module exports something I could even use types instead of dynamic?
b

Big Chungus

11/24/2023, 7:11 PM
Yes
e

Edoardo Luppi

11/24/2023, 7:12 PM
Need to try this out, thanks! Been trying to find a decent solution all day long
b

Big Chungus

11/24/2023, 7:12 PM
There are more elegant ways to import it than require https://dev.to/mpetuska/js-in-kotlinjs-c4g
e

Edoardo Luppi

11/24/2023, 7:13 PM
Had settled with a local package (with a dummy package.json)
Copy code
// The local package with the generated parsers
val localPackage = rootProject.layout.projectDirectory.dir("generated-packages/${project.name}-js")
implementation(npm("parsers-js", "link:${localPackage.asFile.canonicalPath}"))
So if a
file.js
exports
default
a
MyClass
, I could just write
Copy code
public external fun require(module: String): (ctorArg: Any?) -> MyClass
b

Big Chungus

11/24/2023, 7:18 PM
Yep
Wait no, not with require
Since it will return a commonjs module with exports prop
In general it's best to avoid default exports when consuming from kotlin
e

Edoardo Luppi

11/24/2023, 7:20 PM
Considering that I'll move this .js file under
resources
, as you suggested, would it be possible to use
@JsModule
? Or am I stuck with
require
in that case?
b

Big Chungus

11/24/2023, 7:21 PM
But if you export MyClass directly, then you can just slap @JsModule("./path/to/file.js") on external class and be done
e

Edoardo Luppi

11/24/2023, 7:21 PM
Ok you've just answered
b

Big Chungus

11/24/2023, 7:22 PM
@JsModule is the preferred way, but it requires external declarations to define the structure. Require is a hack if you don't have the time for that and are ok with dynamic (or are only importing side effects like css)
e

Edoardo Luppi

11/24/2023, 7:23 PM
Because I suppose
JsModule
will be translated to a
require
call anyway in the end, correct?
b

Big Chungus

11/24/2023, 7:23 PM
Depends on what module system you target
e

Edoardo Luppi

11/24/2023, 7:23 PM
(let's say CJS)
b

Big Chungus

11/24/2023, 7:23 PM
For useEsModules() it will spit out import, for cjs it will be require
There's also @JsName annotation in case the name differs in js or you're importing default export - @JsName("default")
e

Edoardo Luppi

11/24/2023, 7:25 PM
Ok! I think I've got a better understanding of the overall mechanism now. Maybe it's better I quit for today because I'm getting an headache lol Thanks a lot for the explanation and the link!
👍 1
Quickly tested out. This is the only combination that works
Copy code
@file:JsModule("./antlr-gen/JsFaultReportLexer")

package com.hcl.mainframe.proto.parser

@JsName("default")
public external class JsFaultReportLexer(input: Any?)
With this directory layout
b

Big Chungus

11/24/2023, 7:34 PM
Read through the article I've linked, it explains how syntax differs depending on chosen approach and why
But glad to hear you got it working nonetheless
e

Edoardo Luppi

11/24/2023, 7:36 PM
Yup was reading it, just wanted to give the
resources
-way a try! And btw, the test works because I manually copied the
antlr-gen
directory. It seems like when executing tests, resources are not copied under the
testDevelopmentExecutable/kotlin
directory.
Will probably need to wire up an additional task to the test compilation
b

Big Chungus

11/24/2023, 7:36 PM
You need to duplicate them in src/jsTest/resources
Kjs resources are a mess at the moment
e

Edoardo Luppi

11/24/2023, 7:37 PM
Ahhhhhh DAMN, you're right. My brain is fried
b

Big Chungus

11/24/2023, 7:37 PM
Can't blame you, this does work in jvm where tests do see main resources
e

Edoardo Luppi

11/24/2023, 7:38 PM
The overall workflow with ANTLR files generation is a breeze on the JVM target. The JS one... tough.
😄 1
So for myself tomorrow, what I need to do is: 1. call ANTLR to generate files under a temp dir (e.g., the build dir) 2. transpile those files from ESM to CJS with Babel and copy them under both
src/jsMain/resources
and
src/jsTest/resources
3. verify what's the best way to write externals
b

Big Chungus

11/24/2023, 7:43 PM
You might not need 2 since webpack should handle that under the hood during kotlin compilation
Alternatively you can always do useEsModules() in kotlin project
e

Edoardo Luppi

11/24/2023, 7:45 PM
To both the points, I think the answer is no because K/JS doesn't use Webpack for the Node.js target
And Electron (the target platform) doesn't support ESM yet