React streaming example doesn't stream
Hi, I noticed that your template-ssr-react-streaming example doesn't actually stream using the provided Suspense fallback. And no wonder - as documentation states, your root component has to contain the whole HTML structure including an html tag.
Can you show how that it doesn't stream? If I add a log here https://github.com/bluwy/create-vite-extra/blob/8ae5c7449f6b329cbce9339834f6f6115d0110cf/template-ssr-react-streaming/server.js#L68-L73
I can see that there's two chunks being streamed here. The Suspense fallback probably isn't the best example to showcase streaming I guess but IIRC it worked differently in React 18 that made sense.
Hi ! 👋🏼
I'm also having problems with templates that use streaming. I have the impression that the generation on the server side is done well (when I look at the html I see the placeholders generated for the Suspens...) but on the other hand on the rendering in the browser I don't see any streaming, the page is all white and the rendering is done in one go...
I've tried to make a first PR that seems to improve a first problem (https://github.com/bluwy/create-vite-extra/pull/80) that could come from trying to stream directly in the <body> but I'm not satisfied with the result...
Shouldn't we render the html in streaming with the fallback, and once the Suspense component is ready, inject it?
Hmm I seem to be able to replicate the issue now. If I add a long interval in React.lazy(), I can see that the server-side is waiting on that before responding to the request, which isn't streaming.
@CruuzAzul it looks like your fix is on the right track. When there's a root (like main), React will render entirely with the suspense placeholder and then render the suspense result later. When there's no root, React will just wait on the suspense declaration.
The problem when it renders the suspense result later is that React will basically delay the stream, causing server.js to unable to render the remaining htmlEnd to complete the other script tags, causing the FOUC and unresponsive state. This is also kinda why the React docs recommend React taking over rendering the entire HTML because in that case when React tries to delay the stream, the HTML it controls would've already rendered entirely.
Fixing this is a bit tricky, I guess I didn't expect Suspense to also run server-side. An easy fix is wrap the suspense with {import.meta.env.SSR ? null : <Suspense>...} and that makes the lazy loading client-side only.
The proper fix I guess is to have React render the html entirely, but it's a bit tricky since Vite is also trying to control that. The build flow will be more complex than the other streaming setups.
A middleground fix perhaps is to figure out when React is delaying the stream and then we'll render our htmlEnd, then React will handle the rest from there on.
This should be fixed now in v4.0.1
Hi @bluwy ! 👋🏼 Thanks a lot !
Do we need the variable htmlEnded ? We never change it in the code I thinks.
After testing the new version, I noticed another issue that should not exist :
📝 If I update the import of the Card component to simulate a timeout:
const Card = lazy(() => {
return new Promise(resolve => {
setTimeout(() => resolve(import("./Card")), 3000);
});
});
I no longer have the same behaviour between pnpm dev and a pnpm build with a pnpm preview.
With the developer: I have the correct behaviour, the fallback is displayed, everything is streamed, and once the component is ready, it is displayed.
With the build and preview: I have a blank page and I get the rendering once everything is loaded...
@bluwy Should we reopen the issue to analyse this?
Feel free to send PRs to fix this. I currently don't have the bandwidth to investigate but will help review.