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

Server side rendering #47

Open
sne11ius opened this issue May 15, 2019 · 11 comments
Open

Server side rendering #47

sne11ius opened this issue May 15, 2019 · 11 comments

Comments

@sne11ius
Copy link

As far as I could see in the examples, all HTML rendering is done on the client-side. That's ok for "internal" apps. But I would be interested in using kvision for a public website which would highly benefit from SSR (because SEO and speed).

Do you think its possible to do SSR with kvision? Do you have ideas about what would be needed to implement it?

And while we're at it: code splitting for the css would be great too, to improve initial page load/render.

I think this would be great enhancements to kvision, whats your opinion on this?

@rjaros
Copy link
Owner

rjaros commented May 15, 2019

I don't think it is possible. Most of KVision internals is based on specific Kotlin/JS platform features (dynamic types, integration with JS libraries). It just won't work with Kotlin/JVM so we have to forget about any typical JVM based server. The only possible solution would be to somehow run KVision app on JavaScript powered server (e.g. Express on NodeJS), but it seems to be a very complicated idea. Theoretically you can run Kotlin/JS apps in NodeJS, so I can imagine this possibility, but I would rather not be able to implement it.

@rjaros
Copy link
Owner

rjaros commented May 15, 2019

I'v just imagined, we could use a Java based JS engine (e.g. like Nashorn) inside a JVM. Then we could have a Kotlin app compiled to JS, run on a JS engine embedded inside a JVM ... ;-) Sounds insane, but maybe someone, someday would like to experiment with this idea ;-)

@sne11ius
Copy link
Author

I'v just imagined, we could use a Java based JS engine (e.g. like Nashorn) inside a JVM. Then we could have a Kotlin app compiled to JS, run on a JS engine embedded inside a JVM ... ;-) Sounds insane, but maybe someone, someday would like to experiment with this idea ;-)

This sounds good at first, but I think it would be a bad move strategically. I just googled around project nashorn a bit and I get the impression the project is nearly dead [1]. So you would think using nodejs for ssr would be the only route left.

But I got another idea - although maybe a little weird: since the whole UI is described in terms of kotlin code ... would it be possible to use just this for rendering on the server side?
I don't know the kvision code well (nor do I have a good understanding of kotlin2js :D ), but what about giving the Component interface a fun render(): String method to be implemented on the server side just in kotlin?

[1] Some activity hints:

@sne11ius
Copy link
Author

As far as I understand, the "just render with kotlin on the server" approach would mean that every component-module would have to be split up into multi platform projects, am I right? Sounds like horrible mess to me :/

@rjaros
Copy link
Owner

rjaros commented May 15, 2019

There are also two "layers" of rendering. First KVision components render rather simple HTML code through virtual DOM library. Sometimes it's just a simple "div" or "input". And after that the external JavaScript components (date picker, touchspin, bootstrap upload, tabulator and many others) are rendering the complex controls and interactive components. I can manage only this first layer and theoretically it could be transferred to server side. But the JS layer is out of my control. I don't know SSR well enough and I don't how it is implemented with frameworks such as Vue or React.

@sne11ius
Copy link
Author

Thanks for the hint - totally forgot about the js libs. Generally, SSR works like this:

Server side

  • Run code via nodejs
  • Code detects its run on the server (e.g. by checking for node-specific globals like process)
  • Get all data needed for the page. In case of REST services, this could maybe be as simple as prefixing the URLs with something like http://localhost:8080/. Wait for all remote calls to finish.
  • Don't use the data to render anything directly. Instead, populate a store (like redux)
  • Render HTML, use only the state of the store to do that. If there is any component or library that can't work like that, omit it (usually via a special <no-ssr> tag)
  • Inject HTML into page
  • (Optional) Detect which elements were rendered, gather only the CSS required for these elements and inline it
  • Serialize the store state and append to HTML
  • Send everything to the client

Client side

  • Browser renders what the server sent - just like in the old days ;)
  • Initialize store from serialized state
  • Start the application
  • Since the biggest part of the HTML depends on the state of the store and we have the exact state used on the server, the diff will be minimal. The elements omitted on the server should be patched into the dom by snabbdom.

There are two pain points with this approach:

  1. Libraries must support ssr. For example, there is no window variable in node. So if your table library tries to access it on the server side and crashes, it can't render the table. For such cases, you can use the <no-ssr> trick. This would get rid of the error but you wont get the table html on the server side and the more elements you omit this way, the smaller will be the benefit of the whole ssr approach.
  2. It won't work without a store. If you leave it out, your application will at first discard all data-based dom elements (because in the initial application state is empty)... Only to render them again once data from the async api calls starts to pour in.

Overall, I see no reason why it shouldn't work with kvision. However, I'm sure it's an aweful lot of work - and I surely don't expect you to do it.
I'm also not sure if I can muster up the courage to start with this. But maybe I will try some things if I find the time.

@HallofFamer
Copy link

Regarding this issue, I wonder if it is possible to simply skip certain routes/urls, leaving them to be handled by the server side? If we have spring boot as server side, maybe I can have a few routes/urls going with spring boot's server side rendering, while the majority of routes will be handled by KVision client side routing. This way I can have the member-only contents/routes using KVision's SPA, while the guest-available contents(accessible by google crawlers) are rendered by Spring Boot.

@rjaros
Copy link
Owner

rjaros commented Aug 9, 2021

Typical KVision application (frontend app) doesn't use any routes (it uses only client side hash based routing). All routes are handled by the server. So there is no problem in serving any server rendered content. The only problem is the content itself. In a practical server side rendering scenario, the content should be generated from the same, frontend code.

@HallofFamer
Copy link

@rjaros

Interesting. So I can easily have the guest accessible contents to be served by server side with Spring Boot routing, while the member-only contents to be served with the client side routing from KVision?

@rjaros
Copy link
Owner

rjaros commented Aug 9, 2021

Yes. You would probably want to develop fullstack application. KVision fullstack interfaces automatically generate endpoints and routings with /kv/* prefix. You are free to use any other routings just like in any other Spring Boot application.

@reubenfirmin
Copy link

@rjaros The overall goal (speed*) of the original request might be better met with a way to do module splitting cleanly in kvision. If the initial app which is rendered has a small/tiny bundle, rendering will be near instant. Can you see a way to adding some kind of entrypoint bundle that has minimal dependencies, and which can control the download and subsequent rendering of additional modules? If so I vote for closing this ticket and turning it into a feature request to support module splitting.

(*1 I am skeptical about SSR having much of an effect on SEO - google evals javascript, and in any case for a SPA, which kvision targets, you probably want the initial rendered site to be in static html with a place to load the app when requested, in any case.

*2 Perception of client side rendering being slow is often due to framework problems (e.g. react, and a bad use of hooks), and/or inefficient api usage, rather than the browser itself being slow. SSR doesn't really help speed there. A little attention to application architecture works wonders.)

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