I understand that we use Suspense to mark the boundary. If there is no suspense, that means the render will be done in just a single pass, which is the same as the SSR without streaming.
Are we getting any benefit from using renderToPieableStream - the new stream, if there is no Suspense usage in the codebase at all?
Also, would that mean renderToNodeStream would be doing the same thing?
There's no benefit to using renderToPipeableStream() in React 18 if you are not using the Suspense component.
However, there is a major benefit to using renderToPipeableStream() instead of renderToNodeStream() because the latter is actually being depreciated - it also didn't work very well since it could not wait for data.
renderToNodeStream() was basically one step closer to full SSR than renderToString() but still not quite there.
This React 18 Github announcement highlights everything really well.
https://github.com/reactwg/react-18/discussions/22
Hope that helps!
Suspense tells react that there is an async component is getting prepared so when the async component finished data fetching, react will inject that part into the correct HTML spot.
Imagine an Amazon product page, we first see the product images and details about the product and then we see the comments, reviews, footer etc. down below. with renderToPipeableStream() we can first send the top part, images, and details about the product and then rest of page can be loaded. this way you can interact with the part that is loaded while the rest is loading. Because after this part is loaded, react injects its script. this stream is writable stream
export function renderToPipeableStream(children: ReactNode, options?: RenderToPipeableStreamOptions): PipeableStream;
export interface PipeableStream {
abort(): void;
pipe<Writable extends NodeJS.WritableStream>(destination: Writable): Writable}
with renderToNodeStream, you start to send the first bit of HTML to the client, client will see the content but will not be able to interact with it till the streaming is fully done and then the client hydrates it, injects the script. If you were using renderToNodeStream, you had to go over all the pages to see if they had a data fetching function, you had to finish data fetching for all the pages and then you were going to start streaming. this stream is a readable stream
export function renderToNodeStream(element: ReactElement): NodeJS.ReadableStream;
Related
I am creating a web app with React which has a form component, uses Formik field and Yup schema for validation. I am also using Redux to capture some form input to render some other component. Everything works ok, but the initial render time is too slow. But once loaded it works fine and 2nd, 3rd refresh is correct very little render time. I am using create react app.
What is the solution? What should I look for? Chrome Dev Tools saying long function chain is main problem. I don't know where is this chain.
Sincerely,
I am out of clue here, component composition and image optimization is key, it is being said in multiple blogs, but not sure in this case.
As you know the react 18 alpha version which was just released includes :
Suspense and lazy on the server: You can now use and lazy
on the server. Together with the new pipeToNodeWritable method, this
solves long-standing pain points and performance problems with server
rendering:
Code splitting works together with SSR. You don't have to choose one
or the other. React uses your boundaries to stream the page
HTML in visual chunks. React uses your boundaries to
hydrate the page in chunks, improving responsiveness.
More details there : https://github.com/reactwg/react-18/discussions/47
Dan Abramov has developed a demo https://codesandbox.io/s/festive-star-9hfqt?file=/server/render.js
showing how we can set up SSR with react using pipeToNodeWritable, though it is said
we don't have a recommendation yet for how to transfer data from the
server to the client to prepopulate the cache
In a typical SSR app in react/react router, you find the route matching the request, and then you await on all the promises that are within your routes's components.
If you you use redux, you can then set the data into the store and render the html.
Something like that : https://github.com/ilkeraltin/react-ssr-news/blob/master/src/index.js#L42
My question is how would that fit into Dan Abramov's demo ?
In the render.js file there's a createServerData () function, would that be the location where we basically do, what I described above ? (await on route's promises)
I currently have a React app that I'd like to use SSR with. All but one component is pretty much static content, making SSR super easy. Everything but the component is rendered just fine and well right now.
My question is how do I go about rendering this component that needs to first get data? Because it's a complex SVG that gets rendered my line of thinking is that having it "update" once data comes in is a bad move, and it would be better for it to just not exist in the absence of data (with an error message).
So here's my plan: I can add a prop to the component to pass in data from a parent rather than keep it as internal state only. So if data is passed, no fetch request in the component is necessary. From there what I can do is take the static bundle output of the app and, when the page is requested, the server will request the proper data just as the component would. Once the data is received, the server can grab the component from the bundle with regex, add the data as a prop, render the component, and stick it back in with the rest of the already rendered static content.
Is this the correct way to do this? It feels a bit complicated, but that might just be how it's done. I'm not sure.
Your intuitions are correct. In current React (17.0), it's quite cumbersome to do SSR with data-fetching inside components.
What needs to be achieved on a conceptual level is that all data dependencies need to be known upfront, ie. before calling ReactDOM's render. This way, one can access the data in a synchronous manner which allows to do one-pass render on a server.
I don't quite follow your idea to "grap the component from the bundle with regex". One way of solving the data dependency problem is to inject the data into React tree from the root component (ie. ReactDOM.renderToString(<App componentStaticData={data} />)) and make the data-dependent component aware of the fact that it can just grab the data from there instead of doing (asynchronous) call. It's important to note that useEffects are not executed on the server.
Another idea to grab all the data dependencies is to do two-pass render. First one is used as a way to collect all resources used, then we await their completion and inject them as static data into send pass.
Third way is to use one of the React frameworks that provide SSR out of the box. You can have a look at (among many others) Next.js or Gatsby. Depending on your setup, this might be easiest or the hardest way to achieve SSR.
I am slightly confused about the merits of ssr and code splitting and and code splitting done solely on the client.
My thoughts are that server rendering the page first will lead to a better experience without all the javascript having to be parsed and then server rendered.
I am confused how code splitting fits into the ssr model, is it that ssr renders the first hit and then code splitting is done thereafter on the client?
React.Lazy makes a point of saying react.client is all done on the client. How would it differ from code splitting on the server. Is that if you go to a specific route then you retrieve that chunk for the first render?
I understand React.Lazy is all done on the clientside and they have made a real point of saying that. How would it differ if it was done on the server.
Is there any real benefit to ssr with code splitting. Does it not just add complexity?
tl;dr
Depending on your usecase you may use only SSR, only code-splitting or combine both as needed.
Merits of SSR
Better SEO since search bots have markup to work with (and not necessarily dependent on executing javascript) for indexing.
Faster initial render since markup is sent from the server, the browser doesn't has to wait on executing the javascript to render it. (Although the markup will still lack interactivity till react is hydrated client side).
Deliver critical CSS first. The critical CSS for the initial page render can be in-lined, better UX since the loaded markup will already have styles ready.
Simpler route splitting. SSR imo makes it simpler to reason about route splitting your application. For example, you may have different pages for /about and /home which you can route split to reduce bundle size (and preload other routes on client side if needed).
Combining code splitting your components and SSR
It might not be necessary to server render your entire page. For example, consider your homepage (which you wish to server render) includes a Chat component so users can directly ask you questions.
If this component is big you may decide to not server render it so the user can get the most important bits of the page first. This would reduce your initial page load by code splitting this component in your homepage component.
When the browser has parsed the markup it would load your Chat component after the main bundle. This way you could identify and keep your bundle sizes in check.
Only using code splitting
This is a perfectly fine way to build your application imo if you are not interested in the benefits of SSR.
For example, if your application is a user dashboard for authenticated users, it might be better to not worry about SSR at all and just code split your application. Also note that server rendering your application will take more time to send response on server (instead of plain REST APIs) since the markup has to be generated.
Coming to your questions:
I am confused how code splitting fits into the ssr model, is it that ssr renders the first hit and then code splitting is done thereafter on the client?
Yes, kinda. The browser receives the initial load from server, after that client takes care of loading the necessary bits. Now, you may decide to preload your components server side and send everything as well (please check react-loadable which I mention at the end of this answer).
How would it differ from code splitting on the server. Is that if you go to a specific route then you retrieve that chunk for the first render?
lazy is just a cleaner API with support for Suspense for code-splitting. Ideally, when loading a route for the first time you would server render the initial markup and then let the client take care of loading next bits and routing. Imo Next.js does this really well.
How would it differ if it was done on the server.
You may preload all your components or only the necessary bits. Please check the Combining code splitting your components and SSR section.
Is there any real benefit to ssr with code splitting. Does it not just add complexity?
Everything has its own trade-off here imo. As I mention in the Only using code splitting section, its perfectly fine to just use code-splitting if your use case doesn't require the merits of SSR.
Note
Currently lazy (in React v16.6.1) doesn't support SSR completely. You might want to check out react-loadable to handle the cases where you wish to preload components server side.
Server-side rendering
Useful for SEO matters pages
When the page is requested, the server processes the request and builds the final HTML page which is then delivered to the client.
This approach favors SEO matter pages since the final content is available in the first request, therefore search engines are able to index it.
Code-splitting
Useful for pages where content is loaded at different times
If your entire website uses too many resources at different load times, code-splitting is the go-to technique for performance optimization. Instead of having all the resources load with the first request, you delay the loading until the resource is needed.
Implementing both together
Given the case that you have a website with lots of resources and you want to render the entire page requested before handling it to the client, you might want to implement both of this techniques.
React.lazy()
React.lazy() was implemented in React v16.6.0 as a new method of using the Suspense component to do code-splitting.
Note
This feature is not yet available for server-side rendering.
Suspense support will be added in a later release.
To sum up
Suspense + React.lazy() doesn't yet support server-side rendering.
Server-side rendering + code splitting allows for the client to get the requested rendered page without extra resources that aren't needed at the moment.
You are asking many questions here. In my opinion code splitting is useful for larger applications, where your built bundle is just too big for a single load. While server side rendering is useful for smaller landing page style of pages, therefore reducing the compute time in the browser.
I'm using a custom tool similar to react-snap to create a snapshot of my app at build time, as recommended in the create-react-app docs. This generates a static server-rendered version, which I can deploy behind nginx without running react on the server. This works fine.
I'm also using code-splitting to lazily load some components to reduce the initial JS payload. (I use react-loadable, but I'm willing to change that if needed.) It works fine when creating the snapshot, and the HTML is generated correctly, which the user receives correctly, and everything is displayed fully server-rendered without even downloading any JS yet. This is great.
However, during rehydration on the client, the import(...) call for the async loaded component hasn't yet been fired. Meanwhile, the DOM already has the stuff that has to be rendered, from the snapshot.
In this scenario, is there a way to prevent the initial render of a component during mounting, since I already have the content in the DOM?
Also, is it possible to have react's hydration logic run after the import is complete, so that I can prevent any flicker even after the import is complete?
If it matters, the lazy-loaded components are infrequently used routes, managed by react-router.