DEV Community

Discussion on: Server Rendering in JavaScript: Optimizing for Size

Collapse
 
peerreynders profile image
peerreynders
  • Server component - completely static and only the render result gets sent to the client - not the renderer.
  • Stateful component - rendered completely on the server but has client side state (like server-side rendered HTML augmented client-side with regular-elements).
  • Client component - needs to be completely rendered within browser.

For reactive libraries with Template Cloning, there is very little difference between "Server" and "Stateful" components.

I like the notion of a three-tier organization but I don't see why "client components" can't use template cloning. If I understand correctly "stateful" components are bound to DOM elements created by the browser in response to parsing server rendered HTML. If so, "client components" wouldn't be that different from "stateful components" if they bind to DOM elements created by the browser in response the content template being cloned (unless I'm misunderstanding the organizing principles).

And it's the "stateful component" implementation options that expose the limitations of the component mentality. Clearly it's convenient and attractive from an authoring perspective to be able to wrap a presentational fragment with some code that needs to manipulate that presentation to render the visible portions of its state into a single unified package. But that's a self-imposed constraint (grounded in OO-thinking) - it's conceivable that a cohesive unit of code/behaviour may need to present parts itself in multiple, separate locations on the DOM-tree that aren't collocated or related via predictable parent-child relationships. That is, "UI components" may need to become a lot more humble - to the point that they are mostly glorified templates - "UI templates" - that the smart (non-DOM) code can be bound to. So the generally accepted component mindset could be more of an obstacle than a blessing moving forward.

but if the interactivity is sufficient enough do you end up with sort of maintaining two conceptual applications.

That isn't an issue if those two conceptual applications are compile-time artefacts of some unified design-time view - duplication is only an impediment to adoption if the duplication has to be maintained manually. I see the current practice of conflating server and client capabilities into the same component at design and run time to achieve SSR as an unwelcome source of non-essential complexity. It seems to make more sense to separate the relevant facets at design time while providing a means to correlate them and then "weave" them together at compile time.

Collapse
 
ryansolid profile image
Ryan Carniato

To your first question I meant that when you hoist the static template parts(for cloning) you can just not ship them if the component is "Server" or "Stateful". In all cases the render code is basically hydration.

So if something is "Server" you don't have anything to hydrate and your component is basically a no-op. The only code it would have had to clone the node can safely not be included. With "Stateful" it is the similar, but you still walk to add the dynamic parts. You don't ship the static parts. With "Client" though you need to send the static parts since it needs to be able to re-create that part of the template.

The fact that the decision not to send the template is relatively easy and without almost any other code modification you achieve the 3 tiers since the hydration code is mostly what you would have generated anyway. I was just pointing out that "Server" components could be bucketed in with stateful since really only difference between the 3 is include template or not which only the latter does.

In reality we can do this at a subcomponent level since it isn't the Component that is "Client" but rather the control flow branch. But I thought it was easier to talk in terms of components. With proper analysis we can choose exactly which sub-template parts need static templates or not.

With a Component architecture like you might find in a VDOM you actually need to not include the "Server" components in the re-render tree. Current Marko uses a trick where we identify all the topmost "Stateful" components and forward the props up to them and basically treat them like their own entries. The thing is once we are stateful we depend on diffs so all "Stateful" components are "Client" components. Which means you lose the ability for "Server" components to exist under "Stateful" components. In the more granular approach you could have a lot more static stuff under "Stateful" components as long as it doesn't fall under a "Client" control flow branch which is why we are much more excited about this newer approach.


On the comment on interactivity. To be fair there might be something in HTMX that I wasn't seeing. I was just thinking about like Hotwire and the like. Basically a server template that doesn't take the potential for persistent client state in mind will need to go somewhere else.

React Server Components seem to be a way of making this separation in the same tree. But I think a lot of the angle being taken with a lot of JS libraries is to simplify things by abstracting out the server vs client bits behind common interface. Like if you are loading data from the API vs the Database that piece can be hidden behind your useResource hook. I guess there is some complication there but I'm very interested in this follow the data sort of thing where the component doesn't care where it's rendered. That might be idealistic but I'm thinking I'm liking the potential to write our components once at design time and have the compiler split it out. You only can do that if you write your components the way you would in the client as pure templates are insufficient. Of course Marko's newer approach is that these are same thing so I mean there is that.