hi I'm trying to set up a js/jvm multiplatform lib...
# multiplatform
b
hi I'm trying to set up a js/jvm multiplatform library project; are there any samples? getting an error Cannot add a configuration with name 'jvmMainImplementation' as a configuration with that name already exists.
Copy code
import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask

repositories {
    mavenCentral()
}

plugins {
    alias(libs.plugins.kotlin.multiplatform)
    alias(libs.plugins.kotlin.serialization)
    alias(libs.plugins.versions)
    alias(libs.plugins.openapi.generator)
}

group = "at.fyayc"
version = "0.0.1-SNAPSHOT"
description = "Emporix API Client"

kotlin {
    compilerOptions {
        freeCompilerArgs.addAll("-Xjsr305=strict", "-Xannotation-default-target=param-property")
    }

    sourceSets {
        commonMain.dependencies {
            implementation(libs.ktor.client.core)
            implementation(libs.ktor.client.cio)
            implementation(libs.kotlinx.serialization.core)
            implementation(libs.kotlinx.serialization.json)
            implementation(libs.kotlinx.datetime)
            implementation(libs.kotlinx.coroutines)
        }

        commonTest.dependencies {
            implementation(libs.kotlin.test)
        }

        jsMain.dependencies {
            implementation(libs.kotlinx.coroutines.js)
        }

        jsTest.dependencies {
            implementation(libs.kotlin.test.js)
        }

        jvmMain.dependencies {
            implementation(libs.ktor.client.java)
        }

        jvmTest.dependencies {

        }
    }

    js {

    }

    jvm {

    }
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(25)
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}

// do not show beta and milestone versions as upgrades
tasks.withType<DependencyUpdatesTask> {
    rejectVersionIf {
        val version = candidate.version
        val stableKeyword = listOf("RELEASE", "FINAL", "GA").any { version.uppercase().contains(it) }
        val regex = "^[0-9,.v-]+(-r)?$".toRegex()
        val isStable = stableKeyword || regex.matches(version)
        isStable.not()
    }
}
1
c
I've never seen that error, and nothing seems particularly wrong. Just in case, • I always see the
repositories {}
block after the
plugins {}
block • I always see the declaration of platforms (
js {}
,
jvm {}
) before the sourceSets configuration I'm not sure if that could impact it though
b
I fixed it for now by removing the jvm altogether but I don't think that's correct
maybe related to the useJUnitPlatform or java plugin block?
nope
@CLOVIS ordering the js/jvm blocks before dependencies fixed it, how weird
thanks
h
It's not weird, but needed. The jvm/js blocks setup the target and creates the sourceSets. By accessing them before the setup, Gradle does not find the sourceSets.
b
still looking for examples on how to distribute a js and jvm lib btw
h
What do you mean exactly, via mavenCentral as klib/jar? Or via npm (js only)?
b
npm and maven
also running into this IllegalArgumentException: Node.js net module is not available. Please verify that you are using Node.js
looks like CIO does not run on node
and okhttp only runs on android, right?
h
CIO client? I don't use CIO but the JS engine on JS
Yes, but you can use expect/actual (or just HttpClient() without an engine).
b
ah, thanks
how would you write that in commonMain?
do you need to create an "actual" fun main block and implement it in each sourceset?
c
you can just write
Copy code
val client = HttpClient()
in commonMain
b
image.png
then I'm getting that
it looks like you are building your example for browsers only
Copy code
package at.fyayc.emporixapi

import io.ktor.client.*
import io.ktor.client.request.get
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

@OptIn(DelicateCoroutinesApi::class)
fun main() {
    println("yo")
    val client = HttpClient()
    GlobalScope.launch {
        val response = client.get("<https://webhook.site/84e3873b-4d08-4191-bd5a-ad7d7d07524a>")
        println(response.status.value)
        println("this is a test")
    }
}
also using ./gradlew runJvm does not print anything after the get request
so no this is a test output
no stacktrace either
is there some kind of await() that I need here?
launch probably forks/creates a thread and then exits, right?
was runBlocking removed?
h
To get a better stacktrace on JS, use Use
suspend fun main() = coroutineScope {}
and
Copy code
launch(CoroutineExceptionHandler { _, exception ->
                    exception.printStackTrace()
                }) {}
instead of GlobalScope (is it okay on JS, but a code smell IMHO)
runBlocking
is not supported on JS. JS is almost async.
c
also using ./gradlew runJvm does not print anything after the get request
That's expected, you're using GlobalScope, and main doesn't wait for it to finish
use
Copy code
fun main() = runBlocking(Dispatchers.Default) {
    // …
}
h
There is no runblocking on JS 🙂
c
yep
b
right, can't import that 🙂
the suspending main works for the JVM at least, but not JS
h
It does
c
but yeah as Philip said,
coroutineScope {}
will work
h
You can have suspend main on JS
1
b
ah crap
it's a bug
b
removed esmodules and used node build/js/packages/emporixapi/kotlin/emporixapi.js
it hangs for a bit then exits, request is not made
I see print statements right before the get call, then nothing
ah,
Copy code
package at.fyayc.emporixapi

import io.ktor.client.*
import io.ktor.client.request.get
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch

suspend fun main() = coroutineScope {
    println("yo")
    val client = HttpClient()
    println("test")
    launch(CoroutineExceptionHandler { _, exception ->
        exception.printStackTrace()
        }) {
        val response = client.get("<https://webhook.site/84e3873b-4d08-4191-bd5a-ad7d7d07524a>")
        println(response.status.value)
        println("this is a test")
    }
    return@coroutineScope
}
this is how you'd use the example above, right?
h
Yeah
b
TLS sessions are not supported on Native platform
c
🤔 I've never seen that, and I do have HTTPs calls on native
maybe there's something you need to install on the system?
b
had to remove CIO dependency
now it works on both, thank you
👍 1