Comments (7)
Blowing away the DOM may work from a technical point of view but is a pretty jarring user experience. It will nearly always lead to white disrupting flash when the DOM is destroyed and build up again.
from crank.
@benjamingr
The main problem I see, is not how to render the components, IMO, that's already done in the HTML renderer.
The problem is IMO, how to attach event handlers and "forward" the component's generator function to the proper "step" on client side after we got the HTML string from the server.
from crank.
To add two more arguments to why I think @marvinhagemeister is right on saying that this will led to a jarring user experience without hydrating:
-
Recreating the whole DOM tree twice, it's styles, reflows and compositing it's an expensive operation that leads for the browser to have a large impact in the first time to interactive, this is obviously not noticeable in the small example, but very noticeable for the user in a page with 1500 nodes.
-
Also when the user triggers an event in the pre-rendered dom, it will not translate to the new tree and it's listeners, thing that will work seamlessly in a hydrated React page once the listeners are installed. This will happen quite a lot because the pre-rendered tree might be shown in the screen while the browser is still downloading the whole bundle, processing the javascript and executing it, this process can be as quick as ~0.5 seconds in a desktop with local access to the bundle but as long as few seconds in a mobile.
If the issue goes down to user experience, this is a must that has to be taken into account, otherwise crank will be unlikely to be a choice for anything that needs ssr.
To the point from @yurynix of how to forward the generators to the right step, this can be let to be the responsibility of the architecture of the app, and the libraries that hold the serialized state from the server.
For example if you are driving both the ssr and client renders based on fetch state, you can:
-
While in ssr and hydrating, in the server you wait for the responses before fulfilling the fetch promise and in the client you give that response immediately when hydrating from the serialized cache.
-
While reacting to user events in the already hydrated app in the client, you might want to fulfil the fetch promise immediately upon request with the request metadata when there is a cache miss, to leave the app the opportunity to show the loading intermediate component. For this the async pattern you need is a generator, to be able to re-render when the response arrives
from crank.
I just learned about this project so taking a stab:
In both React and crank components hold state and are impure - in crank that state is managed by the language itself (through generators) rather than reinventing the wheel (through array pushing and popping in hooks or through instance state with "fake classes" in classes).
Holding the state as local variables means you can use tooling the language makes available to you instead of rolling something "specific to SSR" kind of how async functions with MobX are easier than Redux because they leverage language tooling.
This means SSR is as simple as just calling .render
on a component. Components work the same way but the generator only runs as long as you want.
Taking the code example of an async component:
async function QuoteOfTheDay() {
const res = await fetch("https://favqs.com/api/qotd");
const {quote} = await res.json();
return (
<p>
“{quote.body}” – <a href={quote.url}>{quote.author}</a>
</p>
);
}
In order to SSR this - you just run it as is (with isomorphic-fetch) or if you want to cache the result or otherwise treat it differently on the server - you just inject the server parts and mock them on the server side.
from crank.
That is, even in regular react SSR is slightly different because components are "less stateful", managing that state in regular JavaScript and just discarding the generators makes things easier.
from crank.
Oh I see what you're talking about now - that depends on how the stores and state is implemented. I'm not sure if the framework already supports hydration - but hydration would require "cooperation" from the stores in order to "progress the generator automatically" on the client.
from crank.
Cross-quoting from Reddit:
Yeah! Right now, you can render components to strings using the HTML renderer, and it works with stateful/async components out of the box! These are the early days of this library, and I plan on creating some kind of meta-framework like Next.js or Svelte’s Sapper, if someone doesn’t do it for me. I looked into creating one, but they almost always involve some kind of advanced webpack magic that I don’t really understand yet.
In regards to hydration, this might be harder to implement given the current internals of the renderer, but my current thinking is what even is the point of hydration? Like, React has a seperate function for reusing existing DOM nodes, but if the outputs are the same, why do we care that the DOM nodes are reused versus blowing away those nodes and rerendering the same thing on the client? I know that in React, server/client rendering mismatches are kind of annoying, so I think I may experiment with the blow it all away and don’t care about mismatches approach.
—Brian Kim
Some responses:
Don’t forget about playing videos. If you return video markup from the server then init the client side, it would interrupt the users experience.
Thank you for the details!
I don't know all the reasons for rehydration but one of the personally more importent ones is: Animations / CSS Transitions will trigger again without the rehydration thingy.
To which he said "excellent points" roughly.
I am not sure that "blow it all away" would not work, however, if the SSR'd rendering framework requested an initial holding state for animations and video, and then loaded in the actual animation/video when it threw the explosives... essentially demanding a clear landing site for the app's dynamic components. Bad for certain kind of pages, ofc, but those pages are often the ones which are most dependent on JS in the first place, so the gains of SSR with hydration (providing a static webpage quickly using a dynamic framework, then enabling a swift transition using the app's diffing powers) were already low.
from crank.
Related Issues (20)
- Restart generator components which return when re-rendered HOT 1
- Context utility wish-list HOT 3
- Precise DOM mutations HOT 1
- Allow async generator components to use `for... of` HOT 2
- `null` vs `undefined` as a way to indicate deleting props/attributes from host elements HOT 2
- Async unmounting/updating
- Better error messages for tagged template function Syntax Errors.
- Call `cleanup()` functions even if component is unmounted HOT 1
- Full-stack (meta?) framework / CLI HOT 2
- Adopt React’s element identity behavior HOT 1
- Errors being swallowed in the second async component of a race. HOT 1
- Export `renderer` and `Renderer` based on environment from `@b9g/crank/standalone`
- The type="text" attribute on input elements is being removed HOT 6
- Use `key`, `ref` and `static` props instead of the variants HOT 6
- Attempting to set up with Vite HOT 7
- HTML in SVG (via foreignObject & `jsx` function) doesn't render HOT 5
- Can't express HTML entities in jsx template strings, e.g. or ​ HOT 9
- When does a render get mounted? HOT 4
- Adding a $key prevents component lifecycle `finally` clause HOT 4
- Keyed elements disappear HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from crank.