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

hfhbd

09/25/2023, 10:44 AM
Is there an option to generate a single plain JavaScript script file from a Kotlin/JS project, which includes all needed dependencies and does not use exports, to include/load this script file in another JS host? The implementation could be optimized/mangled except defined published api which use called by an external host.
e

Edoardo Luppi

09/25/2023, 11:29 AM
Probably https://kotlinlang.org/docs/js-project-setup.html#webpack-bundling Although I've never tried a custom config.
h

hfhbd

09/25/2023, 11:34 AM
Well, I don't need the browser, the host is (ironically) the JVM with a JS engine. I just don't want to write plain JS code and I want to bundle all deps. Is web pack still the correct tool, at all?
e

Edoardo Luppi

09/25/2023, 11:36 AM
I'm not sure what Kotlin uses for stuff like Node, but I know for sure I package my VSCode extensions with Webpack, so I'd say yes
And the final package is a single monstrous JS file
h

hfhbd

09/25/2023, 11:38 AM
Do you have a public config and are you able to mark functions with parameters as entry point/consumable from other JS?
j

jw

09/25/2023, 11:42 AM
kotlin.js.ir.output.granularity=whole-program
e

Edoardo Luppi

09/25/2023, 11:44 AM
Interesting, didn't even know about that, but does that bundle dependencies too?
j

jw

09/25/2023, 11:45 AM
It does!
e

Edoardo Luppi

09/25/2023, 11:46 AM
Well I guess we have the answer then, without any Webpack, cool!
h

hfhbd

09/25/2023, 11:46 AM
And use NodeJS or browser? Should it make any difference?
j

jw

09/25/2023, 11:53 AM
Not really, no. Depends on what module system you use, I suppose.
h

hfhbd

09/25/2023, 11:57 AM
Any
I don't care
option? 😄 I just want to write this js, generate 1 file and pass the call function to the jvm host:
Copy code
function foo(message) { return message.bar; }
Thankfully, I finally get 1 js file, nice. But the resulting js file still uses exports and there is no "static" entrypoint.
e

Edoardo Luppi

09/25/2023, 11:58 AM
Probably depends on what the JVM JS engine supports
h

hfhbd

09/25/2023, 12:01 PM
Hm, I don't know the underlying engine and the docs are (as always) very sparely. But I won't expect a modern engine support modules/exports.
e

Edoardo Luppi

09/25/2023, 12:02 PM
I used Rhino ages ago and I recall CommonJS was supported. Just compile for browser and you should be good
But btw, if everything is bundled together I don't think you should care
j

jw

09/25/2023, 12:07 PM
CommonJS is probably what you want then
Even though things are output in a single file there's still a module system that can be used. The output is basically just concatenated together and isn't fundamentally different than having multiple files.
gratitude thank you 1
h

hfhbd

09/28/2023, 7:47 AM
Thank you for the answers, unfortunately, I still have problems with the modules. I only use the
whole-options
which works nice, and this setup:
Copy code
kotlin {
    js(IR) {
        nodejs {
            binaries.library()
            useCommonJs()
        }
    }
}
Copy code
@JsExport
fun foo(message: dynamic) {
    println("asdf")
}
The resulting js file contains modules and the used js engine does not support it:
Copy code
com.sun.phobos.script.util.ExtendedScriptException: org.mozilla.javascript.EcmaError: ReferenceError: "module" is not defined. (//src/main/resources/script/test-javascript.js#1) in //src/main/resources/script/test-javascript.js at line number 1, cause: org.mozilla.javascript.EcmaError: ReferenceError: "module" is not defined. (//src/main/resources/script/test-javascript.js#1)
Do you know any option to not use modules at all? this is the failing last line:
}(module.exports));
Okay, got it!
Copy code
kotlin {
    js(IR) {
        nodejs {
            binaries.library()
            configurePlainOptions()
        }
    }
}

fun KotlinJsTargetDsl.configurePlainOptions() {
    compilations.configureEach {
        kotlinOptions.configurePlainOptions()

        binaries
            .withType(JsIrBinary::class.java)
            .configureEach {
                linkTask.configure {
                    kotlinOptions.configurePlainOptions()
                }
            }
    }
}

fun KotlinJsOptions.configurePlainOptions() {
    moduleKind = "plain"
    sourceMap = true
    sourceMapEmbedSources = "never"
}
You need to not only configure the kotlinCompileJs task but the binaries too, so I just copied the
useCommonJS()
implementation and replaced the moduleKind to
plain
. Now I need to add a top level function, but this is easy with Gradle using a copy task, because the host (using Rhino 1.7R4) only supports a toplevel function.
gratitude thank you 1
👍 1
e

Edoardo Luppi

09/28/2023, 10:21 AM
Interesting! I want to give this a go too, to check if there is any benefit in final bundle size
4 Views