does someone have a working example of hosting a JS frontend from within ktor server? I’m aware of <...
p
does someone have a working example of hosting a JS frontend from within ktor server? I’m aware of singlePageApplication routing and I achieved something like this like a year or two with a bunch of custom logic, but now I want to use the idiomatic way I’m stuck in a place where I have two projects: the one in Kotlin/JS (React) that produces a working bundle in
build/distributions
, and another module with a working ktor server. What’s the idiomatic way to declare a dependency on the web UI project form the ktor project, copy over the bundle to the ktor module and serve it from ktor? My ultimate goal is being able to create a Docker image with the server hosting the web UI, so I presume the bundle should land somewhere in JVM
resources
this is the closest I managed to get - doing it in the server (consuming) project: • build.gradle.kts:
Copy code
sourceSets {
    main {
        resources {
            setSrcDirs(listOf("${project.buildDir}/js-bundle"))
        }
    }
}

tasks.processResources {
    dependsOn(copyJsBundleToResources)
}

val copyJsBundleToResources by tasks.registering(Copy::class) {
    dependsOn(":web-ui:build")
    from("$rootDir/web-ui/build/distributions")
    into("${project.buildDir}/js-bundle")
}
• Main.kt:
Copy code
routing {
            singlePageApplication {
                useResources = true
            }
        }
I also don’t understand what
react(…)
inside
singlePageApplication
gives over the above. It’s defined as:
Copy code
public fun SPAConfig.react(filesPath: String) {
    this.filesPath = filesPath
}
is it only for the sake of documentation?
👌 1
No copying required
p
hmm, it looks pretty complicated. So you’re wrapping the JS bundle into a separate JAR right? what are the advantages of this approach over putting them in server module’s resources?
b
Not separate, it's added to the classpath of my server jar. Ktor us then configured to serve from resources or alternatively from fs
That way I can have my frontend running standalone during development and have it packaged into the server on deployment
e.g. that particular app is served in both modes kamp.petuska.dev is hosted standalone and kamp.azurewebsites.net is served by ktor.
The setup is quite simple tbh. Just add your js output to jvmRun and jar task classpaths and that's it. The rest is just me manually managing fatJars
p
I’ve just noticed you’re keeping the server and the UI in a common multiplatform module - my setup is a bit different, I have separate modules
b
That's legacy code, here's a wip branch that uses modules https://github.com/mpetuska/kamp/tree/kodex/app
Setup is much cleaner there
p
definitely! thanks!
c
Hey @Piotr Krzemiński, have you heard of Formulaide? 😇 It's been a while
I just copy the generated files to the server's resources: https://gitlab.com/opensavvy/formulaide/-/blob/main/server/build.gradle.kts#L87
p
Hi Ivan, yes, now I recall your project :) so this case is another proof that everyone does it a bit differently, I'm looking for some idiomatic, reusable solution that would hide some of the complexity. But on the other hand, it's not a lot of custom code to write
c
Do remember to setup the ConditionalHeaders plugin, it helps a lot with performance of static files: https://gitlab.com/opensavvy/formulaide/-/blob/main/server/src/main/kotlin/formulaide/server/Main.kt#L158
Indeed I'm not sure what an idiomatic way would be. I like that approach because it's very simple to set up and understand, and seems to fit all use cases well.
👍 1