Search code examples
kotlin-jskotlinc

How to compile a Kotlin file to JavaScript?


Hi I am getting started with KotlinJS on Node and I've put a very simple kotlin file and I want to compile it using the raw kotlinc-js compiler. Without using gradle

package main

fun heavy() {
    (1..10_000_000).forEach { it*it }
}

fun main() {
    heavy()
    println("Bye JS")
}

Here's the make command I've tried yet without success:

build-js:
    kotlinc-js main.kt -output main.kt.js

It compiles fine, but when I attempt to run node main.kt.js:

throw new Error("Error loading module 'main.kt'. Its dependency 'kotlin' was not found. Please, check whether 'kotlin' is loaded prior to 'main.kt'."); ^

Error: Error loading module 'main.kt'. Its dependency 'kotlin' was not found. Please, check whether 'kotlin' is loaded prior to 'main.kt'. at Object. (/home/nanospicer/KotlinProjects/KotlinScripting/main.kt.js:2:9) at Module._compile (node:internal/modules/cjs/loader:1101:14) at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10) at Module.load (node:internal/modules/cjs/loader:981:32) at Function.Module._load (node:internal/modules/cjs/loader:822:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12) at node:internal/main/run_main_module:17:47

Ok, so I figured it's missing the kotlin runtime. I'll try same argument as the JVM compiler: -include-runtime which leads to the error:

error: invalid argument: -include-runtime info: use -help for more information

Then I tried:

build-js:
    kotlinc-js main.kt -kotlin-home "/mnt/c/Program Files/JetBrains/IntelliJ IDEA Community Edition 2021.2.1/plugins/Kotlin/kotlinc/" -libraries "/mnt/c/Program Files/JetBrains/IntelliJ IDEA Community Edition 2021.2.1/plugins/Kotlin/kotlinc/lib/kotlin-stdlib-js.jar" -module-kind commonjs -main call -output main.kt.js

But it still leads to the same error. I also tried removing the libraries flag and it didnt work either


Solution

  • I've found the culprits.

    I basically created a nodejs project from IntelliJ IDEA and took a quick read through the gradle tasks which hinted me that it was preparing a node environment for me under the hood.

    I took a quick glance at npm.js and found that in fact there's a package called kotlin which is the javascript's stdlib for the compiler.

    I finally tweaked the build command on my Makefile to use a module-kind of common-js and it worked out!

    //Definitive main.kt I ended up using
    fun heavy() {
        (1..100_000_000).forEach { it*it }
    }
    
    fun main() {
        heavy()
        println("Bye JS")
    }
    
    

    Install kotlin's stdlib using npm:

    $ npm i kotlin --save
    

    And my Makefile build command looks like:

    $ kotlinc-js main.kt -module-kind commonjs -main call -output main.kt.js
    

    A small breakdown of the arguments:

    • -module-kind commonjs it's telling the compiler to generate the code-style for a node project (not quite, but you get the gist)
    • -main call determines whether the compiled module should invoke the main function. This is because if we set the value to noCall we're not gonna run the main function and it may behave just like a library.
    • -output main.kt.js the name I chose myself without any reason, as long as it's a .js file you'll be able to run it but I wanted to keep it like this to compare it to another main.js file I was generating!