The Gradle™ Way to include javaScript client projects in JVM apps

I’m just learning how to use Kotlin/JS in a Kotlin JVM-backed Spring Boot project. This project has two subprojects, client (Multiplatform/Js), and webapp (JVM).

For reference, here is what I threw together tonight: https://github.com/tristanjuricek/device-analytics

Right now, if I build the Kotlin/JS project, I can copy the built “browser distribution” from client/build/distributions/client.js (and .map file) to webapp/src/main/resources/public and reference the build. This works fine, and I can do something funky like have that automatically update, I guess. But it doesn’t feel very “Gradle-y”.

What I’m wondering is how other projects have approached this sort of thing in the past.

I realize I may end up switching the webapp to a Multiplatform-style build, which may have this as a concept … somewhere. But I’m wondering, if this wasn’t a fancy Kotlin multiplatform build, say, the client was some javaScript-based system, what’s the approaches people have used that works well here?

1 Like

I think I’m dealing with the same thing, need to include jsMain output in jvmMain or front/backend so that the jvm can serve up JS that was compiled from kotlin… I’m not really sure why I dont just serve up js files and angularjs from the backend, but I guess I’m teased by the promise of doing full stack in a single language…

I had the backend serving up three.min.js but that was before I had jsMain. The ktor mpp examples dont seem to work. But even those seemed to use the from keyword to copy paste resources between platforms like your suggesting… by the way, I cant find any good docs on what this “from” keyword really does but it appears to be the only way to achieve this. I think I have to do a from, into jvmMain/resources or something but that doesnt seem like a great way.

An approach that I’ve recently found that I seem to like is here:

The main setup:

  1. There’s a shared multiplatform project that outputs both .jar for the server and .js for the frontend.
  2. A frontend project is just a straight browser SPA project - as in, it builds a single UI page for right now. I could see this being broken down into different webpack builds.
  3. A backend project is just a Spring Boot project.

The main trick is that the backend uses processResources to grab the output of the frontend project.

	processResources {
		dependsOn(":frontend:browserWebpack")
		from(project(":frontend").projectDir.resolve("src/main/resources")) {
			into("static")
		}
		from(project(":frontend").buildDir.resolve("libs/spring-kotlin-fullstack-frontend.js"))  {
			into("static")
		}
	}

So here’s just an example of deploying the SPA as part of a Spring Boot project, as an “embedded resource”. Which, to be honest, isn’t always what you want to do, but, can be handy for quick and dirty internal project things.

What I like is that the real edit and debug cycle is provided solely within the frontend project. You don’t launch it within the backend really, until you’re doing integrated testing. There’s a task called :frontend:run that actually launches a special webpack dev server. This is slick.

This is where my earlier approach kind of failed, I was not really separating the javaScript frontend platform bits from the JVM backend bits. Really, it’s just a dependency that happens to deploy as resources. So processResources makes sense - but only for the final build. Otherwise, you probably want fancy webpack edit/debug cycle.