Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for the JVM #7

Open
cromefire opened this issue Jul 19, 2024 · 12 comments
Open

Support for the JVM #7

cromefire opened this issue Jul 19, 2024 · 12 comments

Comments

@cromefire
Copy link

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
Copy link
Owner

rjaros commented Jul 21, 2024

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
Copy link
Author

cromefire commented Jul 21, 2024

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
Copy link
Author

cromefire commented Jul 21, 2024

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
Copy link
Author

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
Copy link
Owner

rjaros commented Aug 2, 2024

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
Copy link
Author

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
Copy link

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
Copy link
Author

cromefire commented Aug 5, 2024

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...)

@apatrida
Copy link

Not addressing this early means what, that it'll be a major overhaul and in the end this framework ends up like Koweb without allowing free access to server-side code while in the JVM during SSR.

We would end up with yet another web framework that previously JS web people are unlikely to use, and then the JVM backend people will be left out of a combined frontend/backend code base again.

Or is this allowed in some other way? Why repeat the same half-end goal and not address this early and finally have full stack Kotlin in one code base?

@rjaros
Copy link
Owner

rjaros commented Sep 18, 2024

It's not that simple. The primary goal of this project is to have single code base that runs in the browser but at the same time allow to render html on the server side. Free access to the server side code sounds nice, but can't be achieved with this primary goal (because such code just can't run in the browser). In my opinion you are thinking more about classical server side rendering (like PHP or JSF).

This issue is about running browser code (or better: code targeting browser) on the JVM instead of NodeJS. But it would still be browser code, so it will use http client calls to access the backend, without any direct access.

The main problem, as I said earlier, are external types. There are no external types on the JVM target. So we would need to reimplement the whole browser / dom API with expect/actual types. What's worse, we won't be able to use external types when interacting with many JS components used by the framework. Everything would need to be duplicated with expect/actuals and reimplemented with external types on JS/Wasm targets and also with some custom implementation on the JVM. And that's just really a lot of work.

@cromefire
Copy link
Author

cromefire commented Sep 18, 2024

What I recently came across is that kotlinx.html is already reimplementing some stuff possibly, so maybe some synergies may be used there. But possibly it won't be easy to get this working well without architecting the framework for this from the beginning on.

Also my expectation would be to be able to substitute the HTTP calls with direct calls/calls into the HTTP server without TCP, but that would be up to the user to implement using expected / actual or some interface or whatnot.

@rjaros
Copy link
Owner

rjaros commented Sep 18, 2024

When writing a real fullstack application with current architecture of Kilua you work with the frontend using common js/wasmJs code (which gives you external types, direct access to browser and DOM apis and full JS components interop) and with the backend using standard JVM code (with full access to all JVM libraries). I'm not really sure if going to fullstack in the sense of common multiplatform target is in fact an advantage and the "right" way. Writing code inside a "common" module with all three JS, wasmJS and JVM targets seems like more losses than gains to me - no externals, no browser interop, no JVM libraries, unless using expect/actuals for everything.

Yes, I can imagine a simple code base, which renders some interactive data, works in the browser and renders SSR using just the JVM. It seems totally possible. But I'm just not sure this kind of framework will allow to create more complex applications easily and effectively. Maybe we just need yet another framework :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants