Is it possible to have hot reload of Kotlin code w...
# http4k
m
Is it possible to have hot reload of Kotlin code with http4k server? Not just static resources and templates, but the actual Kotlin code (in case you use some Kotlin HTML DSL rather than external templates). Would be nice during development of web apps, and seems like a common feature of JavaScript/TypeScript based web servers.
d
We haven't implemened one yet. If you know of a decent mechanism to make it work then suggestions are much appreciated. Of course, which typescript it's mostly handled through the build tooling - yarn etc. not sure if there is something equivalent for gradle
m
j
You used to be able to do this sort of thing using kotlinscript but the future of that is now kind of a mess so no point to develop that, probably. ( https://blog.jetbrains.com/kotlin/2024/11/state-of-kotlin-scripting-2024/ ) JVM can hot reload code using classloaders, but that would mean creating separate build targets and/or clever packaging for hot reloadable things. Otherwise using test to test the output, rather than web-page-reloading might work...
m
Very tangential to this thread but I'm very mad at that scripting article. IMO scripting is great and still very much supported but the article looks like a deprecation notice 🤷
d
@mbonnin 💯 . We use the scripting capabilities quite heavily for the http4k toolbox.. They have updated it with this note, so maybe all hope is not lost...
Copy code
TL;DR: Kotlin scripting remains an essential part of the Kotlin infrastructure. We continue to support it in the experimental state, and we are concluding certain experiments and reducing the number of scripting-related technologies that we provide and actively develop.
💯 1
m
I think JetBrains agrees as well, both Gradle scripts and main.kts files are core technologies, there's even language about improving them:
Copy code
We will continue to develop the `.main.kts` script type, which is already helpful for simple automation tasks. We have plans to extend its functionality and streamline IDE support.
The deprecated stuff (KotlinScriptMojo, kotlin-scripting-ide-services, JSR-223) TBH I never heard of them before 😅
j
To my reading, which I admit can be totally wrong, as its very confusing article, kotlin script that is embedded within a kotlin program is now dead. Gradle (not really kotlin script I'd argue) and main.kts (not embedded) are not how I'd find kotlin script useful
m
My reading is that the Kotlin scripting host APIs Custom Scripting APIs are far from dead, they just stay experimental like they've always been 🤷 Agree the wording is confusing though
They just can't remove these APIs without effectively killing build.gradle.kts and main.kts (which, I would be very surprised if that happens)
m
I tried to use
gradle run --continuous
, but I could not get it to work. It seems like others have tried and failed as well: https://stackoverflow.com/questions/47383516/how-to-auto-reload-hotswap-with-gradle-and-scala
gradle build --continuous
seems to work, but doesn't really get all the way towards hot reload 🤷
m
Copy code
I'd tried gradle run --continuous but didn't work because the run task is never-ending and seems like --continuous doesn't start a new build/task unless the previous one has finished.
Welp yea, if it doesn't cancel the previous task, that won't work. Sorry for the red herring.
Which leaves me wondering how yarn does it 🤔
m
Maybe yarn needs support from the server framework?
Otherwise using test to test the output, rather than web-page-reloading might work...
Well, not really feasible if you are prototyping a UI and want to tweak the look and feel of it.
The best I came up with so far is to run it from IntelliJ IDEA (through
gradle run
task, or the main class directly), and manually press Ctrl-F5 to re-run. Would be nice if IntelliJ could watch the sources (which I believe it does anyway) and re-run on any change.
a
I'm curious what you would like hot-reloading for. I totally get wanting to prototype template changes quickly, but I think your question wording implies it works as you'd expect. But when the Kotlin code is most likely going to be business logic, the case for hot reloading is less clear. Http4k was designed with TDD in mind, so I imagine any changes to the Kotlin code would best be tested with JUnit. Are you trying to develop without tests? Or is it not good enough for what you have in mind?
m
If you are developing web services, which exposes a JSON API or something like that, then there is no need for hot-reload, and automated testing is suitable. But if you are developing web applications, with HTML/CSS UI, then automated testing is more difficult and won't take you all the way.
a
I wonder if a layered approach might help you test the business logic independent of the HTML views?
m
I am specifically thinking about Hypermedia-Driven Applications, where the server delivers HTML, with the htmx framework.
a
Yeah, I understand. It's been a while since I've developed an application like that. When I worked with Spring, the app was far too slow to be tested, so we relied on hot reloading for changes to business logic. But in http4k, I think you have better options. Maybe if you create a
Service
layer, that can be tested easily. And then build your
Views
on top of that, where you can rely on the template hot reloading for prototyping. Could something like that work?
m
Well, not if you use a Kotlin DSL for HTML generation instead of a template system 🤷
a
Ah, of course
In that case, I totally get why you'd want hot reloading. I wonder how Spring, Quarkus, and friends do it 🤔
j
It compiles things itself. Not how I'd probably do it, but I guess it works. https://github.com/quarkusio/quarkus/tree/main/core/deployment/src/main/java/io/quarkus/deployment/dev
I think you could get a similar result by making a classloader and loading the compiled dsl code using that. You can then make another classloader when the compiled files change...
m
Maybe we should lobby to make Jetbrains include this feature in IntelliJ IDEA? Does anyone have any connections at Jetbrains?
d
standard way is to raise a ticket on youtrack and then poll for upvotes
j
If you just wanted to save/compile/restart: (Linux keys, but sure mac is similar) Ctrl-s (save all) Shift-f10 (restart running app) It may be easy enough..
Tbh, shift-f10 will save anyway...
d
I've been playing with this and have hacked something together in the incubator. If you upgrade to 5.44.0.0, then add:
Copy code
implementation("org.http4k:http4k-incubator")
to gradle, then you can run with:
Copy code
import org.http4k.core.Request
import org.http4k.core.Response
import org.http4k.core.Status
import org.http4k.testing.HotReloadServer
import org.http4k.testing.HttpAppProvider

class HttpApp : HttpAppProvider {
    override fun invoke() = { req: Request -> Response(Status.OK).body("my hot reload") }
}

fun main() {
    HotReloadServer.http<HttpApp>().start()
}
Under the covers it is watching the source directories and then using gradle to build on changes. It's in no way perfect - multi-module builds almost certainly won't work with it without modifications - but I've just tried it on a simple single module project and it seems to work ok, so maybe it's something we can work on for the future at some point. On failure it spits out the gradle compilation error to the log. Feel free to have a play and feed back - or even better PR upgrades to it 🙂 ,
👀 1
❤️ 1
🔥 1
m
I just tried with https://github.com/mikaelstaldal/htmx-http4k-html-builder/ it works, but is a bit cumbersome to use with
HttpAppProvider
. It also seems to rebuild twice for each change.
d
I don't get that problem here. Try playing with the parameters.
i suspect it might be too slow in rebulding. Try taking the code from github and playing with the sleep to see if you can debounce it
the watch thread has a hardcoded timeout - i;ll adjust that now to parameterise
m
OK, so about the API, I'm not sure I understand how to use
HttpAppProvider
properly. I got it to work, but with quite convoluted code.
d
it's literally just a hook for creating the Http Handler
It needs to be attached to something so that it knows what to rebuild. If you can come up with soemthing better than happy to take a look!
m
But you need to define a class?
d
yes - - i tried it with a lambda but the identity of the class generated changes every time you build.
m
I see, makes sense.
d
yeah - it's a bit clunky for sure. The nice thing about it is that it's all in the IDE without any remote debugger nonsense if you want to debug
m
A bit unfortunate that you have to deviate from the server as a function approach, but I don't have a better idea.
d
The HttpAppProvider should be a test harness. For Prod usage you shouldn't need it at all - just create your server as usual
a
For that to happen, you'll need either: • two main functions • interpret an env var to not set up the hot reloader • have the hot reloader interpret an env var to not hot-reload
Frameworks obviously use the third method. Not sure what would be ideal here
m
Anyway, very promising indeed, and also agnostic to what template engine (if any) you use I suppose.
d
This is definitely v0.1 - which is why it's in the incubator for the moment.
👍 1
a
Really cool POC
m
Yes, with some polishing, it could become really useful for web app development.
> you'll need either: > two main functions I think that would be good. The second main function (with hot reload), can be manually run from within the IDE.
d
the hot reload server is just a wrapper which can sit in another main. You do need something which will create a test-env version of your HttpHandler (or Polyhandler), but that's pretty standard for me at least - setting up something that uses in-memory fakes and storage etc..
👍 1
m
I think I get it now, it can be as simple as this:
Copy code
class HotReload : HttpAppProvider {
    val app: HttpHandler = // create your app here
    override fun invoke() = app
}

fun main() {
    HotReloadServer.http<HotReload>().start()
}
👍 1
r
Just wanted to say that this is super useful! 🙌 Seems to be working well enough for me
👍 1
114 Views