rjaros / kilua

Composable web framework for Kotlin/Wasm and Kotlin/JS
https://kilua.dev
MIT License
122 stars 5 forks source link

Support for the JVM #7

Open cromefire opened 1 month ago

cromefire commented 1 month ago

I know this is a pretty big ask and may be further in the future even if attainable and if you are interested, but similarly to how SSR works on Node JS, the real killer feature if you'd be able to do the SSR in Kotlin/JVM with direct access to server resources (and possible future integrations into the server side frameworks then maybe?) and then hydrate the whole thing in the frontend using web assembly.

That'd cut down a lot of complexity for full stack development with the JVM, as you don't have to hast a separate node js server anymore (also making deployment way easier) and you can maybe even cut down some latency with saving the resources wasted on the actual HTTP transaction.

A use case I can immediately think of is placing it directly into a spring gateway server and directly routing and dispatching the HTTP request right from the gateway (also taking advantage of the resilience like circuit breakers) to the micro services instead of having to go through another hop.

On the technical side maybe this may also be able to be be achieved with a limited feature set as it wouldn't need to actually live render the DOM, but only spit out a prerender at the end of the rendering (similarly to haw the kotlinx.html library only produces a static snippet of HTML server side at the end of the day). Compose shouldn't be a problem as it's available for the JVM, but what is probably an issue (but maybe can be isolated and abstracted so it's only used on the js side or for more advanced functionality) is the web manipulation APIs like HTMLElement which is used for rendering HTML Tags with Tag<>. Although that should also be an issue on NodeJS, right? To be honest I haven't really played around with the NodeJS SSR as it's quite the PITA and I try to do as little in the JS ecosystem as I can..

rjaros commented 1 month ago

Hello. In theory it could be possible, because most Kilua code is plain common code. To add a new target only expect/actual code needs to be implemented. As it sounds simple, Kilua contains its own DOM and browser api implementation in the kilua-dom module which uses external JS types (like Promise, RegExp, kotlin.js.Array) as actuals, and it would not be easy to reimplement them on the JVM. There are also some actuals in other modules implemented with js() function and native JS calls. I suppose that's also quite a lot of work. One more thing to consider is the fact, that JS/Wasm runtimes are single threaded, and that assumption is used in many places to simplify some things. JVM is multithreaded, so it could behave differently. But you are right, it would be very nice to have support for JVM target. It's definitely something I will consider when I have more free time. And of course, contribution are welcomed :-).

cromefire commented 1 month ago

As it sounds simple, Kilua contains its own DOM and browser api implementation in the kilua-dom module which uses external JS types (like Promise, RegExp, kotlin.js.Array) as actuals, and it would not be easy to reimplement them on the JVM.

That is what I thought, but is it maybe possible to stop it down a bit more to maybe like a core implementation for SSR and then a full implementation for the actually running thing? I'd imagine things like event handling wouldn't be needed and maybe there's something more that could be reduced, but then again, I don't know how easy it is to remove some stuff into its own module.

JVM is multithreaded, so it could behave differently.

Yes, but it's usually only multi threaded if you want it to be, maybe something like an UI-Thread restriction like Android has would be releastic, if the concern is with the user using multi threading. It would only require some gates, that could easily be then just be a no-op for JS/WASM, but generally it works quite well for Android. And I'd als consider that also the users can't use much threading as their code would have to run in both JS/WASM and the JVM.

And of course, contribution are welcomed

I'm generally interested, but I do suffer from the same issues with not having enough time. Maybe towards the winter when stuff slows down a bit.

cromefire commented 1 month ago

I started a few tests in #8 and while I think this may still be feasible, it'll not be easy.

I think there is also the need for some major changes before it's even possible, such as switching from global objects to using the coroutine context or some context receiver to store global stuff, such as the css modules, as there'd be multiple instances rendering in parallel potentially. Maybe let me know your thoughts on the topic, I'll maybe do some tests on which approach even works.

cromefire commented 1 month ago

What is definitely necessary is probably a look at the current SSR as well and what's actually needed, because it shouldn't have access to all of the DOM APIs on NodeJS as well, so it seems it gets there without that in SSR.

rjaros commented 1 month ago

When adding JVM target, we can no longer use external types. It seems to be the most problematic issue, because even if reimplementing everything on JVM could be possible it would require major changes to the whole project architecture.

cromefire commented 1 month ago

Yeah it'd probably mean that the approach had to be slightly different, relying on less JS on the API surface and moving the JS stuff more to the backend.

Some stuff like events wouldn't be needed of course as you don't need that for SSR only at runtime.

NorbertSandor commented 1 month ago

external JS types (like Promise, RegExp, kotlin.js.Array) as actuals, and it would not be easy to reimplement them on the JVM

Maybe GraalVM's Javascript support could be used instead of reimplementing them? (I don't know the details, it is just a quick idea.)

cromefire commented 1 month ago

Nope that's maximum pain, GraalJS does not ship with any types from the HTML spec, so no setTimeout, no URL, no fetch and no HTMLElement.

I'm currently running some JavaScript SSR code on GraalJS and I literally had to reimplement the JS URL myself using the JVM's URI... (Which is even more pain once you realize that JS's URL type is actually 2 different behaviors in one, one for "special" URLs and one for the rest which behaves completely different...)