Next up on our Kotlin Multiplatform journey I thought it would be interesting to look at bringing PeopleInSpace to the web….using Kotlin/JS and making use of same Kotlin shared code that we’ve used on other platforms. In line with project in general we’re going to make the minimum changes needed to support this (these posts are primarily aimed at (a) giving people a “flavor” of what’s possible, and (b) providing minimal setup needed to get someone up and running using particular technology). Note also that this is heavily inspired by this excellent Kotlin/JS codelab.


In a Kotlin/JS project we’re writing our web client in, as you’d expect, Kotlin and making use of Kotlin DSL for HTML (and also, in this case, React and Kotlin Wrappers for React).

The following is all our Kotlin client code (shows very basic list of people in space). Note it makes use of PeopleInSpaceApi() (and Assignment data class) which are part of our shared Kotlin Mutiplatform code.

fun main() {
    render(document.getElementById("root")) {
        child(functionalComponent = App)
    }
}

val App = functionalComponent<RProps> { _ ->
    val scope = MainScope()
    val api = PeopleInSpaceApi()

    val (people, setPeople) = useState(emptyList<Assignment>())

    useEffect(dependencies = listOf()) {
        scope.launch {
            setPeople(api.fetchPeople().people)
        }
    }

    h1 {
        +"People In Space"
    }
    ul {
        people.forEach { item ->
            li {
                +"${item.name} (${item.craft})"
            }
        }
    }
}

The following is the index.html file used. It contains root div element which above Kotlin code refers to and also includes web.js which is generated from that Kotlin code.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>People In Space</title>
</head>
<body>
<div id="root"></div>
<script src="web.js"></script>
</body>
</html>

Gradle updates

These are the main Kotlin/JS related updates to build.gradle.kts for shared code module.


    val jsMain by getting {
        dependencies {
            implementation(kotlin("stdlib-js"))

            // Coroutines
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:${Versions.kotlinCoroutines}")

            // ktor
            implementation("io.ktor:ktor-client-js:${Versions.ktor}") 
            implementation("io.ktor:ktor-client-json-js:${Versions.ktor}")
            implementation("io.ktor:ktor-client-logging-js:${Versions.ktor}")
            implementation("io.ktor:ktor-client-serialization-js:${Versions.ktor}")

            // Serialize
            implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:${Versions.kotlinxSerialization}")

            // SQL Delight
            implementation("com.squareup.sqldelight:runtime-js:${Versions.sqlDelight}")
        }
    }

And following then is build.gradle.kts for the web module. Note dependency on common module which is where our shared Kotlin code resides.

plugins {
    kotlin("js")
    kotlin("plugin.serialization")
}

dependencies {
    implementation(kotlin("stdlib-js"))

    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.3.5")
    implementation("org.jetbrains.kotlinx:kotlinx-html-js:0.7.1")
    implementation(npm("text-encoding"))
    implementation(npm("abort-controller"))
    implementation(npm("bufferutil"))
    implementation(npm("utf-8-validate"))
    implementation(npm("fs"))

    implementation("org.jetbrains:kotlin-react:16.13.0-pre.93-kotlin-1.3.70")
    implementation("org.jetbrains:kotlin-react-dom:16.13.0-pre.93-kotlin-1.3.70")
    implementation(npm("react", "16.13.0"))
    implementation(npm("react-dom", "16.13.0"))


    implementation(project(":common"))
}


kotlin.target.browser { }


To test this out: from root of project you can run ./gradlew :web:browserDevelopmentRun --continuous which will automatically open http://localhost:8080/ and also update that whenever you make changes to any of the Kotlin/JS code.

And the following is the very basic UI you get (an exercise perhaps for reader is to use the React Kotlin wrappers to make something a little less basic :) )

People In Space Kotlin/JS Client

The above code is included in PeopleInSpace repo (in web module).

(purpose of providing this is primarily to help “close the loop” and provide way to post feedback/ask questions ec (in absence for now of that functionality in blog itself).