Kotlin-js, dce & closure compiler

I’ve been playing with kotlin-js (see the ui directory in this project). In the documentation it is suggested that using the google closure compiler & dce plugins might be a good thing for production code. I’m struggling with both and the documentation is less than helpful on this front currently and there seems to be a general lack of examples using both. Google is of course less than helpful when most documentation for this is years old and not relevant for current versions of kotlin-js.

Basically the only thing that actually works in a browser is the enormous js file produced by the kotlin-js file. I’d like a properly minified version of that with source maps please.

Here’s my gradle file. I’m attempting to import left-pad as a proof of concept. I’ve enabled dukat via kotlin.js.experimental.generateKotlinExternals=true in gradle.properties.

plugins {
    id("org.jetbrains.kotlin.js") version "1.3.61"
}

apply {
    // this plugin minifies the kotlin js output. Several bugs currently with this (e.g. multiple npms having an index.js)
    plugin("kotlin-dce-js")
}

group = "com.jillesvangurp"
version = "1.0-SNAPSHOT"

repositories {
    jcenter()
}

val closureCompiler by configurations.creating

dependencies {
    implementation(kotlin("stdlib-js"))
    testImplementation(kotlin("test-js"))
    // needed for the google closure compiler, which is recommended to minify the output of dce
    closureCompiler("com.google.javascript:closure-compiler:v20200112")
}

kotlin {
    sourceSets["main"].dependencies {
        // set kotlin.js.experimental.generateKotlinExternals=true in gradle.properties for dukat to do its thing

        implementation(npm("left-pad", "1.3.0"))
        implementation("org.jetbrains.kotlinx:kotlinx-html-js:0.6.12")
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.3.3")
    }
    target {
        useCommonJs()

        browser {
            webpackTask {

            }
        }
    }
}

tasks {
    register<Copy>("copy-index-html") {
        from("src/main/resources/index.html")
        into("build/packaged")
    }

    register<Copy>("copy-dce-html") {
        from("src/main/resources/dce.html")
        into("build//kotlin-js-min/main")
    }
    // does not work because of module errors
    register<JavaExec>("googleClosureCompileDceJs") {
        dependsOn("copy-index-html","copy-dce-html","assemble","runDceKotlin")
        classpath = closureCompiler
        main = "com.google.javascript.jscomp.CommandLineRunner"
        args = listOf(
            "--compilation_level=SIMPLE_OPTIMIZATIONS",
//            "--process_common_js_modules", // errors with a  ERROR - [JSC_INVALID_MODULE_PATH] Invalid module path "kotlin" for resolution mode "BROWSER"
            // nope, this doesn't work either
            "--js_output_file=build/packaged/${rootProject.name}.js",
            "build/kotlin-js-min/main/kotlin.js",
            "build/kotlin-js-min/main/kotlinx-coroutines-core.js",
            "build/kotlin-js-min/main/kotlinx-html-js.js",
            // this is left-pad, which the dce plugin fails to name properly. Also, you can only have 1 file called index.js
            "build/kotlin-js-min/main/index.js",
            "build/kotlin-js-min/main/${rootProject.name}.js"
        )
    }

    // processes the output in distributions (12M) and produces a similarly sized file that does not work (unlike the original)
    register<JavaExec>("googleClosureCompileDistributionJs") {
        dependsOn("copy-index-html","assemble")
        classpath = closureCompiler
        main = "com.google.javascript.jscomp.CommandLineRunner"
        args = listOf(
            "--compilation_level=SIMPLE_OPTIMIZATIONS",
            "--js_output_file=build/packaged/${rootProject.name}.js",
            "build/distributions/${rootProject.name}.js"
        )
    }
}

There are multiple problems that I’m chasing with this.

  • gradle run --continuous works fine but the output in distributions is huge.
  • the dce output is a lot smaller but I’ve yet to find a way to make it work. I attempted to load this via the dce.html that explicitly names each module in the (supposed) order they need to be loaded.
  • I’ve defined two variants of using the closure compiler.
    • The first one works on the dce output and this doesn’t load (some error about modules when you load the html).
    • The second one works on the output in distributions (non dce) this produces a similarly huge file that unlike the original does not load

Both of the tasks copy files to a packaged directory.

I’d appreciate feedback on how to improve this and get it in a working state.

I’d also humbly suggest updating the documentation with working configuration for dce and the closure compiler. Even what I did seems useful (despite not producing useful output) since it at least has a working config for pulling in the closure compiler, which is something that required a bit of research on my side as absolutely nothing with the kotlin dsl is straightforward.

Currently the tests don’t work. I suspect the leftpad dependency is guilty.

1 Like