The Benefits of Server Side Rendering Over Client Side Rendering
medium.com
medium.com
> SSR throughput of your server is significantly less than CSR throughput. For react in particular, the throughput impact is extremely large. ReactDOMServer.renderToString is a synchronous CPU bound call, which holds the event loop, which means the server will not be able to process any other request till ReactDOMServer.renderToString completes. Let’s say that it takes you 500ms to SSR your page, that means you can at most do at most 2 requests per second. BIG CONSIDERATION
You can also consider running it on a Kubernetes cluster with auto-scaling turned on.
This is situational, I think. My work mostly involves applications that do significant back-end processing for most requests, and my SSR is always done using a framework that has pre-compiled code doing the rendering rather than an interpreted language. (Perl and C#.) This combination adds a lot of pre-render computing and optimized rendering, which adds up to SSR being a good choice.
I'm not sure what that says about when CSR would be a good choice. If your requests don't do much back-end processing, but still have a long (500ms?) response time, that seems like you're doing something wrong rather than an opportunity to use CSR. Maybe you've chosen a poorly-performing rendering framework. Maybe you're trying to render too-large a page (which would be even more of a problem client-side.)
Let's say you've got a request that does SSR and takes 500ms, with 450ms of that time spent processing the request and 50ms spent rendering the response. If you switch to CSR, you still have to wait 450ms to process the request, and you've got to serialize the response data (eg: render it to a more concise format than html) which is going to take some of that 50ms you're trying to save. So, where is the blocking you're talking about? How does CSR make it go away?
What you wrote sounds like you're describing a singleton that handles all rendering for all requests, and can only handle one request at a time. If that's the case, your framework is a toy and you need to ditch it for something that can handle multiple concurrent requests independently of each other.
I get offloading some rendering (that server time adds up) but meet me half way. At least show me some content while the rest loads.
I have seen an application login page size 5mb, full of js. Because it downloaded the full application to the client before rendering the login page.
I'm not experienced with Node.JS, but something hogging the main event loop of an asynchronous server with a long computation sounds horrible. It'll mangle your throughput, and it'll create some really strange latency spikes for unrelated requests, because the slow computation blocked the event thread from delivering the response of another request. Is this not as much of a problem practically, or would you isolate that SSR code from REST code in different application instances?
In a threaded server like java application servers or go applications, that should be a non-issue since requests are handled in mostly independent threads. It might increase the necessary compute resources some, but that's expected when moving work to the server side.
I think you are doing something wrong if your tender time is more than a few ms.
But there's a middle ground in practice. Public-facing website that users might hit from a search engine? Obviously render it on the server, and if required progressively enhance it. Something more akin to a web application? Server-side rendering makes everything slower and more complex without benefiting any users. If you aren't using Node on the server, it's even more complex.
I really hate that this is the case. I had this firm idea in my head – "every URL is an HTML page, and users should be able to take that URL and request it using Curl or whatever, and see the content of the page". In practice, we were developing a highly-interactive, domain-specific application that relied heavily on client-side scripting to be realistically useful for users. There were no users without JS that I was able to find. We were doing a huge amount of work to follow a rule of progressive enhancement, that in practice slowed down the experience for users and, benefited nobody, and made development ~ an order of magnitude harder.
Well, it of course depends on what your content is, but you can still use a cache service before.
I installed an infrastructure for an e-commerce for a client. They use Magento. I installed a Varnish in front of it and it goes really faster than without. Most pages are, in fact, static pages (home, categories or products), the dynamic part are ajax loaded after content rendering (like prices or stock) so it's a blast for UX.
Of course it will make no (well, less) sense for a SPA. But for content websites, I think it's more logical to do SSR than force to load the whole JS files to see what's on the page.
Edit : typo
If your `renderToString` is taking 500ms you should really consider using `renderToNodeStream` [1]. It will significantly reduce TTFB and runs asynchronously, letting your Node.js server handle more incoming requests. This [2] blog post goes into more detail.
Also, if you don't want to use streams, Rapscallion [3] provides an asynchronous alternative to `renderToString`.
[1] https://reactjs.org/docs/react-dom-server.html#rendertonodes...
[2] https://zeit.co/blog/streaming-server-rendering-at-spectrum
What baffles me is that this is a long time. In that time, you've got about a billion CPU instruction executions. If you include GPUs, they can render multiple frames of complex scenes to million+ pixel buffers in that time. And people are having trouble rendering a string?
If you have a good network between systems, each request of any form to a backend service will introduce at least 0.5 ms of response time due to datacenter RTA, so once you hit 250 queries, that's that. And 250 queries are just one n+1 problem somewhere.
Not sure if the benchmarks still hold now that React 16 is out, but there's definitely overhead in the general approach.
> HTTP can only send strings/bytes, so it makes sense to start there and skip the overhead of building up a virtual DOM representation first. There’s a reason string based templating languages are so much faster than our modern frameworks using a virtual DOM implementation.
Unless you can use your loadbalancing to split requests with a risk of long-running synchronously tasks away from instances doing fast work. We're doing something like this - we got some really ugly legacy code around, which tends to abuse and overuse the application servers JDBC pool regardless of how we tune it. This causes every other request on that instance to crash and burn. This becomes even more fun if a customer retries the same request 20x and the load-balancer does round-robin. So we route the bad requests to a single martyr instance and everything works fine again except for this broken old code.