I thought the idea was to render it server side just once, then have the client take over for all future requests? In which case it's 10x slow for the first page load, but all future requests are just hitting API endpoints and can be fairly fast?
Sure, but every user has to do that initial page load. If all initial page loads are slow and expensive, it affects the user experience and costs money.
Also, if you start getting requests faster than you can do the initial render, each subsequent user has to wait in line longer than the one before. Your server-side framework won't even show you how long people waited for a TCP connection.
But they're going to have to wait for the initial page load either way, whether it's rendered server side and sent over or they're shown some static content until its rendered client side?
I guess it depends on which direction you're coming from. From a traditional server side point of view, you're reducing the server work to just that first page load and making the client do the rest.
If the Server rendered page is not user specific and is generic for all users then it can be cached and served quickly. Then only potentially one user would experience a slowdown and you can serve much faster.
Of course then you get into the fun of cache management and invalidation.
Elixir Phoenix has a game-changing approach here because of how it compiles templates. Effectively, the static part is always cached (until the template changes), but the dynamic part is never cached. Nothing to manage.
Correct, except that initial app load time for un-cookied users with cold browser caches is a critical metric, since it largely determines whether they'll keep using your app. Fortunately, those are the scenarios where server-side caching can have a decent benefit, since you're essentially rendering the same view to all such users.
There can be (though you’d be surprised- there’s rarely such a thing as a non-identifiable user nowadays). Just pointing out it’s a very big conditional.
For example: I work at Bleacher Report and our non-logged-in users get data customized for them. That can be as simple as GeoIP data or can be us knowing (and inferring) what articles or content they’ve seen.
The permutations are quite large.
Now some blog, or a very simple app won’t do something like that (hell, they might not have the depth of content to be able to) but it’s reasonbly common to have that requirement on large sites outside of v.limited pages (like login/signup etc)
initial app load time for un-cookied users with cold browser caches is a critical metric, since it largely determines whether they'll keep using your app
This is "bounce before document.ready()?" How does it compare to "bounce before ad networks/API calls finish" and "bounce before end of autoplay video?"
I'm thinking that with all the other API goo in many mainstream/mass-media sites, "initial app load time" is something users are probably pretty tolerant of, unless "load time" includes stuff beyond the page becoming interactive.
Since we're talking about SSR which happens before anything else, latency is going to push out all load-time metrics equally.
> I'm thinking that with all the other API goo in many mainstream/mass-media sites, "initial app load time" is something users are probably pretty tolerant of
It's all relative. Presumably you're competing on some level with those mainstream/mass-media sites, so users will punish/reward you if your site takes more/less time to load than average.
Modern JS frameworks try to solve this problem by inlining critical CSS and JS into the head for anything above the fold, and loading the rest dynamically.
They include a comparison with using ES6 Template literals (native JavaScript string interpolation), and saw 10x increase over React. The native string interpolation actually came out just behind serving straight static files. JavaScript CPU performance is actually quite high among interpreted languages.
So to answer your question more specifically, no I don't think it is clear. What this is specifically isolating as the performance problem is that using React as a template renderer on the backend is not performant, not because of NodeJS performance, but because React is realistically not really specialized for this.
All no, but quite a bit, in our prototype for our next gen codebase. Was quite nice because we had a lot of 'legacy' JSPx code that we transformed into JS code using a bit of one off programming with some clean up afterwards.
I do this. It’s surprisingly effective, both in actual performance and developer productivity. The one area where it is useless however is for mutating DOM. It’s easy enough to create DOM using template strings, but if you say need to render something and then mutate it later on in you render function, it becomes terrible since you either have to do tricky string manipulation, actually create the DOM and use methods to mutate it, or use some framework at which point you may as well just give up on template strings altogether.
But for any case where you’re basically going in the one direction, i.e. data -> DOM and not changing things once rendered it’s great.
Couldn't tell you, but it's not really relevant. The post I'm replying to says that it should come as no surprise that NodeJS template rendering is slow, and I just meant to point out that the article is quite specifically isolating ReactJS rendering as slow, and has nothing to do with NodeJS or JS at all.
well depends, I doubt that native js string interpolation is written in javascript at all. so basically it is javascript, but since you are using the native interpolation you probably go trough a c interface. or some kind of extremly optimized path.
I don't understand how this can be your takeaway since you can see how fast Pug is in comparison. The article is clearly singling out React's slow render speed.
So I thought the entire point of SSR was to speed up initial page load - if you pre-render all the static parts of the page, including what happens after routing, but before any API calls, so that your webserver can cache that static HTML for that route and serve it up. What this means is that the user immediately sees much more of a rendered HTML page, rather than seeing a blank page for 2 seconds and having to wait to download and run a massive JS bundle first.
That's part of it, but getting viewable content to the user as soon as possible is just as big. Without SSR, the user has to wait for the JS to download, parse, and execute before they see anything on the page.
OK from single core $10 VPS you will be able to serve
1,080,000 unique initial loads per hour
and depending on your pattern of traffic say 15,000,000 in a day could you remind me what the issue is again?
It's a real issue, my startup's react SSR times are ~5 seconds of blocking the node thread on my $40 droplet. It's about 50% react. Our pages are way more sophisticated than your average page with like a query and a form, though. There are many ways to make faster though, one of which is to simply configure your CDN properly.
What on earth? Our entire app is React+Redux based, gathers a bunch of unique user data per-request from various apis and we still get ~40-120ms response times (and that's on CDN cache misses).
Hell, our Node server's connection timeout is 3 seconds and we only ever hit that due an APIs tanking or something.
No, I opened it on my iPhone X, and regular scrolling (moving my finger up / down the screen) doesn't move the webpage. Instead, I have to try and click the scrollbar on the right hand side (on my iPhone!) and then move the scroller in the opposite direction as I'd swipe.
On iphone sc chrome browser, what they've apparently done is completely reimplemented scrolling;
the website has its own scrollbar, on top of which chrome renders its own, and the site seems to be scrolling in place of the browser, as the "smooth-scrolling" behavior is entirely gone, as well as other little things like scrolling past the end of the page and being bumped back up
what exactly are the bottlenecks? Done some profiling or benchmarks across your codebase? You say blocking node thread and how exactly are you using threads in node? Maybe resource contention is the actual blocking instead of your ssr pipeline. Lots of variables to look for but it still won't match 5 seconds unless you're doing something very wrong. Anyways there's always a choice for writing hot code in a performant language if you know one...
our renders are compute heavy because it is so dynamic (most of today's apps aren't). Think of it this way. Virtual DOM is like a spreadsheet. You only want to recompute the stuff downstream of what's changed. That's basically what React's render-tree pruning is all about. But there are a couple problems.
First, naive server rendered React isn't diffing anything at all, it recomputes the whole virtual dom from scratch every time. So there isn't any render-tree pruning since we're not doing a diff. That's what the walmart-labs patches help with, since obviously a lot of SSR'ed components aren't changing between SSRs, that can be reused, and we can be fast again.
Second, React.js views are more than just banging html together, it also has to call a bunch of functions as part of that process. For example client side sorting, or map/reduce/filter. So if those functions are expensive, your views are slow, even if the html itself isn't all that complex.
Third, since much of our "view rendering" cost is actually computation not directly related to making html, React can't reuse pieces of those computations anyway. You'd need to code your "math" in terms of React components even though there's no html associated with them.
Fourth, if your dataflows are dynamic enough, like a spreadsheet, even if React actually could optimize those computations (which it cant), it wouldn't even be helpful, because while Views are trees, many computations are not. For example, in a spreadsheet: Edit cell C7, quick what is the tree of computations you can skip? The question doesn't even make sense, because spreadsheets aren't trees. Spreadsheets do complicated graph dependency tracking, with cycle analysis and all that, in order to make this fast. React doesn't do that.
As an example of how dynamic Hyperfiddle is, go to http://dustingetzcom2.hyperfiddle.net/ and in the top toolbar click "data" and then click "dev". Dustingetzcom2 is not coded in javascript, its coded in data, and you edit the data live in the dev pane, and the right things update live as you make changes. That's why the render computation is so expensive.
I'm sorry, I'm looking at your example link and you should be getting rendering times in the sub 40ms range. Unless that's not a representative example of course.
No need to try to explain why you think it is slow based on your understanding of React.
Facts are always better. Good news is: I suspect you have no React issue. How is your NODE_ENV? Set to production?
After looking at your website, you have no perf issue caused by React itself! Remove the blinking cursor made with setInterval, and use CSS animation for that. You'll see :)
That link has the data points you are looking for, react SSR problems are well understood and documented and have been for some time now, that repo is a year old
If you spend 20K in developer time to optimize for few hundred/month savings you are not going to be saving much (and that is not counting the cost of maintaining that extra code over time)
Given the latencies shown in the article, if it's 30x that it'd probably take a few hundred ms to render. I'd view that as unacceptably slow; your milage may vary. Also, I suspect 30x that is optimistic for a complex site; it is a single small table.
400m sessions a month doesn't really sound like that much...
Latency still matters though. A stack that can render things in 50ms likely ends up simpler than one that takes 500ms, where things like caching templates, esi, start being introduced to compensate for latency.
Note that React doesn't do streaming HTML in the traditional sense. You can't send out initial HTML while you wait on an API response, for example. Instead only the serializer is streaming. Your app renders to a VNode synchronously and then the serializer traverses the VNode, synchronously, and streams the strings out as it goes. This is why streaming is only a little bit better in these numbers.
If/when React gets real streaming it will compete better with traditional templating engines, most of which don't do streaming. If you use Node.js and want a traditional templating engine that uses JS template literals and does do streaming, check out my project: https://github.com/matthewp/flora
Isn't the whole point of server-side rendered React to render it just once, when building the website, and then serve it as static HTML/JS/CSS assets using a static webserver?
In my view the user-specific parts and frequently updating data should be rendered on the client side. The pre-rendered HTML should contain the less-frequently changing information that is important for SEO.
Given the option, and pretending it were just as easy to implement either, why would you wait until the document loads to fetch resources via Javascript when you can render the content on the server?
The article points out one downside: React's render-to-string faculties are slow.
The other is for performance/seo where the initial markup for the app is generated and served to the client as HTML, then the React app bootstraps on the client and takes over managing the DOM.
More and more sites are using React for general purpose server-side rendering, even if the site isn't a single page app. I believe that's what the article is targeting.
I'd love to see a side-by-side comparison to Marko.js (https://markojs.com/). It has a lot of react-like features, but was built from the ground up for SSR speed.
If you're on the fence about server-side rendering being needed for your webapp don't do it! As a team of two with one engineer, I decided YAGNI and instead focused on the responsiveness of the React and Redux-based web application. It is very snappy to load and our (paying) customers are happy.
You might not need SSR. I don't. I expect there will be more work to optimize it and eventually it'll be obviously a good idea. But you don't need it right now if you're working on a SaaS product.
We did this recently with a small app that needs to be fast. The relatively simple page that you see when you first visit the site is rendered with plain old Rails, then when the user interacts with the page (based on DOM addEventListener hooks) it causes additional React components to be mounted and rendered.
Originally I’d hoped to be able to render a basic version of the page with Rails, then ‘enhance’ it with React - ie render <button>For</button> with Rails, then when React has loaded, replace it with a React component. But I couldn’t find any details on using it this way, and given time constraints choose the simplest option.
This is something we've done in the past, and it works well. In fact, the ability to do this (usability is important to us so progressive enhancement is a lifesaver) is why we looked at react in the first place.
It's the other way around: you might not (in fact, probably do not) need React.
Start with server-side rendering, and move to React if your application's dynamism demands it. Most applications don't. It's painful to see so many websites building huge, slow, JS-rendered monsters for one or two dynamic elements per page. Unless you are Facebook (and have your JS cached within one hop of every internet POP in the world), server-side rendering is going to yield performance wins for nearly all visitors.
Well that is a whole other debate. The best thing about React is common patterns. Second best is the availability of components. I've worked with JavaScript for a long time -- the Backbone.js days were painful. It was easy to accidentally leak event binds, code yourself into a corner, etc. The jQuery days were almost better in some ways but still had some real pain points.
You missed that I'm working on SaaS and a web application. Client-side state is important -- each of my customers can load up most of their state to client-side and the performance is great. This is the whole point of client-side apps. Get rid of all that round trip latency sending HTML to the client of every click. Get rid of your complex server-side framework. Client-side is simpler if you learn and embrace it (and don't need server-side rendering). It's also much easier to have a consistent UX with client-side state.
So use what is appropriate for you use case. For mine, that is 100% client-side no doubt. You can't beat the performance for an application.
"You missed that I'm working on SaaS and a web application"
I didn't miss that. SaaS means "software as a service", and doesn't imply anything about the complexity of your UI. Plenty of SaaS companies use server-side rendering. Likewise, "web applications" were being written long before React was a thing.
Also no, you don't have to do a full server round-trip for every click, any more than you have to send JSON back to your Reactionary UI for every click.
So sure, if you can truly load all of your data in one big JSON blob and do everything else client side, then I guess you're in the 5% of people who can benefit from React. The other 95% should use a good server-side rendering framework and get things like low latency, URL routing, progressive enhancement and SEO-friendly pages for free, and build the few dynamic elements on their pages with a simpler, more robust technology. I never said that React isn't useful, just that it shouldn't be the default choice for most people.
But I have zero use for SEO-friendly pages -- all my client-side pages are behind a login-wall. It isn't one big blob of JSON -- it's multiple endpoints. With HTTP/2, multiple small requests are fast.
> build the few dynamic elements on their pages with a simpler, more robust technology
This is a horrible idea that has worked poorly for so many projects. At one potential employer, they did this and their app had a message view with a read count. They didn't care the read count didn't update -- you had to reload the whole page for it to update. Those are the kind of inconsistencies that the above approach encourages because it's not cohesive.
Can you do it? Yes. Should you? No, not in my book.
I've got low latency, I have client-side URL routing, I have no need for progressive enhancement -- it's just more complexity that neither I nor my customers need. These are all great ideas if you have a public website and need to cater to a wide range of visitors. I don't. I'm very happy to be able to only have to support the last couple major versions of each browse.
"I've got low latency, I have client-side URL routing, I have no need for progressive enhancement"
Again, maybe you're in the 5% of "web application" users that are not actually web applications, but rather, "browser apps that download some data once in a while". If so, great. Most people aren't in that group.
Also, just to clear this up: client side URL routing is not URL routing. It's an ugly hack to make up for the fact that you can't use URLs for their stated purpose. It's honestly sad that we've wandered so far from the norms of the web that URLs have lost their meaning.
It's not an ugly hack at all. It works well, the browser history works properly and the interaction is just as if the pages were being fetched from the server. At any point in time, the user can do a hard reload and the page will rerender as it did before. The URLs are the same as if I was doing server-side rendering.
So I would ask you at this point to turn this all around. Look at it from my perspective. I've been doing fullstack for more than a decade (professionally, hobbyist for twice as long) so I've done plenty of server-side rendering in frameworks like Ruby on Rails, ASP.net MVC, etc. I've contributed (as lead) to open source gems that have over 800k downloads. So I have invested a lot of time into the server-side.
But today, with client-side, there is a huge simplicity factor. You can only get to it after wading through the turbulent waters of "flavor of the week" client-side projects and noise. But when you do get through that and identify your pillars to build on, this is what you have:
* all of your complexity is on the client-side for web
* you can make a simple fairly clean REST or GraphQL backend that will work with multiple clients (web, mobile, etc)
* for at least REST, you no longer really need things like an ORM on the server-side as all of the endpoints are simple and basically fetching a single data type (I use SQL with PostgreSQL so I would say a table here but it depends on implementation)
* HTTP/2 reduces the cost of small requests so complex things like GraphQL aren't really necessary -- you can stay with REST without a penalty
Is there complexity? Is it different? Does it challenge the conceptions of those used to fullstack? Yes. But there is real value and simplicity here too that you might find if you're willing to put aside your hard and fast rules and try something new.
URLs are addresses of resources on the internet. They're parsed by your browser to request resources on another server.
If you've rewritten this functionality in JavaScript to support storing application state in your single-page application, it may "work well" but it is, in fact, a hack. If you've done this to support storing application state in your web application that sometimes has to actually talk to servers on the web, it's an abomination, and a complete violation of the way web browsers are supposed to work. The fact it is a currently popular hack does not change the nature of the thing. Lots of bad ideas were once popular (remember when everyone wanted to build SPAs in Flash?)
"for at least REST, you no longer really need things like an ORM on the server-side as all of the endpoints are simple and basically fetching a single data type"
If your problem is that you don't want to use an ORM, then don't use an ORM. Likewise, there's nothing stopping you from writing a server-rendered webapp with single-datatype endpoints. You can use HTTP2 with server-side rendering. None of these things are enabled by React.
If these are truly the arguments in favor of a particular client-side stack, it's clearer to me than before why so much of this thick-client stuff is terrible.
None of these arguments are for a specific stack. React has little to do with any of this. We're talking about underlying technologies that enable the web to be used as a platform for application development.
My point about an ORM is that your API becomes so simple you don't require a lot of complexity that is required with server-side joins of data in order to render a view. That is gone. No need. I'm giving you examples assuming you can extrapolate them to a bigger picture.
The history API is a standard. The various "routing" JS toolkits are hacks built upon that feature.
"My point about an ORM is that your API becomes so simple you don't require a lot of complexity that is required with server-side joins of data in order to render a view. That is gone. No need."
Yeah, I understood your argument the first time you said it, just couldn't believe you were making the argument. If you don't like joins (related: why do you think you need an ORM to join?), don't write your server-rendered endpoints to use them. The one technology has nothing to do with the other.
That said, as soon as you want to achieve reasonable performance and scale, you will rather quickly find it essential to return multiple pieces of data in a single API call.
I've been a web developer since the beginning, so I understand this frustration with the current generation of web developer that reaches for React first purely because it's trendy with complete ignorance of the strengths of traditional approaches.
However, you are throwing the baby out with the bathwater. Client-side rendering saves server resources, and allows a single API to power web and mobile apps. A pure API is easier to optimize, and is generally a sensible separation of concerns. Of course this doesn't come without overhead, but you don't have to have Facebook-level complexity for this architecture to make sense.
"However, you are throwing the baby out with the bathwater. Client-side rendering saves server resources, and allows a single API to power web and mobile apps."
I don't believe I am. There are certainly uses where I openly acknowledge that using a React is a good idea. If you're building something that needs to be a single-page application, for example, then I grant you that concerns of SEO and URLs and whatnot are superfluous. If you have a totally dynamic site, coupled with a Facebook-esque guarantee that your assets are nearly always in the user's cache, and a huge team of front-end engineers to optimize your code, great. But again, that's a tiny minority of teams.
All webpages are "client-side rendered", so that's a bad use of words. That said, JS-based rendering only "saves resources" if you don't count the bandwidth of the user, the amount of code needed to display a page, render speed, time to first render, and so on. I can't count the number of Reactionary sites I visit on a daily basis that hang for 10+ seconds before rendering or peg my CPU -- and nine times out of ten, they're rendering static content. It's an epidemic, caused by people making bad technical decisions, and even big sites like Instagram get it wrong on the regular (Instagram, in particular, pegs my CPU so often while looking at photos that I believe their secret business model is to mine bitcoin in my browser.)
A pure API may be easier to optimize, but unless you've transferred the time you're saving to front-end optimization, I guaranteed that you're punishing your users -- particularly those who are on low-bandwidth connections and/or mobile devices -- with lower performance and higher system demands.
The difference there is that it's very hard to port a non-JS server-side-rendered site to React if it turns out you do need to. Whereas it's relatively easy to port a React application to additionally do server-side rendering.
The other difference is that I'm having a hard time imagining a scenario where someone is getting blindsided by "damn, it should've been a SPA after all!"
I'd be wary of all of the technical decisions that were made if the decision-maker knew so little about the requirements that they couldn't even call that shot correctly.
Of course, on a long enough time scale, all bets are off.
> The other difference is that I'm having a hard time imagining a scenario where someone is getting blindsided by "damn, it should've been a SPA after all!"
I've seen it happen more than once. Start with what looks like a straightforward form flow, seems like it should be fine in rails or whatever. Then it turns out some fields depend on other fields, so you've got to dynamically show/hide parts when other parts are set. And doing a server roundtrip, even AJAXey, is just too slow. So you put a bit of client-side Javascript to handle that. And then as the product evolves the interrelations between the form elements become more and more complex and businessey, and you have more and more logic split or duplicated between backend and frontend.
This is something a lot of people just don't get. And with react's serverside render, you don't get a trashy 2010-era SPA, you have an SPA that is also an MPA. It's literally the best of both worlds with porting your redux to reactnative for Android/iOs just around the corner.
No matter what system you use for server rendered pages most likely you will have to hit a database just to render out the site. These days that's a bad idea when we should be building progressive web apps that can fetch and cache content as needed from services but the entire app can live offline and even cache data in local storage to enable it to have at least limited offline functionality.
That really is dependent on use case though. In my current project, I want the most up to date data possible so no caching. In reality, it is cached locally in the browser state and soon, I will be pushing data to update that browser state (based on other users activity in the same tenancy).
I think generalizing to "we should be building progressive web apps" is harmful. You should do what is appropriate for your use case.
> I want the most up to date data possible so no caching
This seriously doesn't mean "no caching" and shows a real lack of understanding about caching.
You state that people should so what is appropriate for use case, though your other comments here go completely against that and are cargo cultist in the extreme. I think perhaps, when you say "should do what is appropriate for your use case" you actually just mean "what I think you should do".
It is not the kind of caching that the post I'm replying to is advocating ("the entire app can live offline and even cache data in local storage"). I mentioned the caching I am doing to point out things aren't so simple. I do mean quite literally that none of my API HTTP responses have a caching header (assets are coming from CDN with very long cache life).
It might be more fruitful to try to explain why I go against that instead of simply saying I do without a rational argument that can be responded to. If anything, the thread pretty clearly revealed someone is extremely biased to server-side web frameworks and is unaware of the progression of client-side web APIs.
These results are not surprising to me but it's great that they were published because people have been very quick to jump on the hype bandwagon for these kinds of projects.
I think that the idea of the isomorphic JavaScript app never actually worked in practice. MeteorJS already had a really good go at it.
Sharing JavaScript modules between the client and the server is great but when you start to pretend that the backend and the frontend are the same environment, you're bound to run into all sorts of problems and create inefficiencies.
The kind of performance penalty incurred by server-rendered React is bound to make your system vulnerable to DoS attacks or at best make it unnecessarily expensive to operate.
When programming abstractions shift too far away from the reality of the underlying architecture, you will start paying dearly and the cost won't be worth it in the long run.
In my opinion, the client-server divide is a fundamental aspect of multiuser applications and no amount of abstraction can make it go away.
For this reason, we don't use SSR for pages that change often, and turn it off completely for authenticated users. Some performance analysis showed it was actually slower in the average case than shipping the JS and having the client render it themselves, especially with a hot cache.
This still provides what we wanted anyway; the ability for pages to easily be viewable without JS and easily indexed by search engines.
It would be worth verifying that NODE_ENV=production is set during these benchmarks (I see no mention in either the article or the source repository.) Running in development mode has a significant performance impact.
NODE_ENV=production definitely wasn't set based on some basic testing I did (that's my PR there), which accounts for the atrocious performance.
Also, the React component is created on each request instead of just being created once. Unless one's goal is to specifically colour the perception of React, I don't understand that decision alongside the code for Pug which precompiles the template a single time.
(Also declaring the map function outside the component and not creating a closure makes for a tiny extra boost.)
It's disappointing to see that the article took off to this extent given how misleading and inaccurate it is.
Hello Anatoli. Thank you for this. It was clearly an oversight on my part, not intentional to make React look bad. I have added a note on the article and will run the tests with the correct settings and your PR with further optimisation.
Then you should withdraw the article until you get real numbers. This utterly misleading data (as of now) is going to be picked up by search engines and other blogs.
Add: on a positive note, this aspect of React is worth benchmarking. Thank you for that.
The author mistakes increasing concurrent request as being some sort of proxy for concurrent users. Once you have maximized rps or maximized cpu, increasing concurrent just artificially hurts your average latency.
Max RPS equals number of users you can serve per second. Concurrency should just be tweaked until you eliminate the network latency of your test framework.
133 comments
[ 4.1 ms ] story [ 177 ms ] threadAlso, if you start getting requests faster than you can do the initial render, each subsequent user has to wait in line longer than the one before. Your server-side framework won't even show you how long people waited for a TCP connection.
Of course then you get into the fun of cache management and invalidation.
See http://nathanmlong.com/2016/11/elixir-and-io-lists-part-2-io... for explanation.
Isn’t that the whole point?
That's a big, important, if.
For example: I work at Bleacher Report and our non-logged-in users get data customized for them. That can be as simple as GeoIP data or can be us knowing (and inferring) what articles or content they’ve seen.
The permutations are quite large.
Now some blog, or a very simple app won’t do something like that (hell, they might not have the depth of content to be able to) but it’s reasonbly common to have that requirement on large sites outside of v.limited pages (like login/signup etc)
https://css-tricks.com/building-skeleton-screens-css-custom-...
This is "bounce before document.ready()?" How does it compare to "bounce before ad networks/API calls finish" and "bounce before end of autoplay video?"
I'm thinking that with all the other API goo in many mainstream/mass-media sites, "initial app load time" is something users are probably pretty tolerant of, unless "load time" includes stuff beyond the page becoming interactive.
Since we're talking about SSR which happens before anything else, latency is going to push out all load-time metrics equally.
> I'm thinking that with all the other API goo in many mainstream/mass-media sites, "initial app load time" is something users are probably pretty tolerant of
It's all relative. Presumably you're competing on some level with those mainstream/mass-media sites, so users will punish/reward you if your site takes more/less time to load than average.
So to answer your question more specifically, no I don't think it is clear. What this is specifically isolating as the performance problem is that using React as a template renderer on the backend is not performant, not because of NodeJS performance, but because React is realistically not really specialized for this.
But for any case where you’re basically going in the one direction, i.e. data -> DOM and not changing things once rendered it’s great.
Might help with some of those pain points
It uses tagged template literals to render to the DOM, so on the server side it could fall back to vanilla string interpolation.
[1]: https://github.com/PolymerLabs/lit-html
[1] https://github.com/WebReflection/hyperHTML
EDIT: Yeah, looks like it's always worked that way. Maybe I was thinking of another lib.
https://github.com/styfle/react-server-example-tsx/blob/4586...
What on earth? Our entire app is React+Redux based, gathers a bunch of unique user data per-request from various apis and we still get ~40-120ms response times (and that's on CDN cache misses).
Hell, our Node server's connection timeout is 3 seconds and we only ever hit that due an APIs tanking or something.
As I said, our app is sophisticated
Is this how you get your kicks?
the website has its own scrollbar, on top of which chrome renders its own, and the site seems to be scrolling in place of the browser, as the "smooth-scrolling" behavior is entirely gone, as well as other little things like scrolling past the end of the page and being bumped back up
I would love an article detailing your experience and measurements.
First, naive server rendered React isn't diffing anything at all, it recomputes the whole virtual dom from scratch every time. So there isn't any render-tree pruning since we're not doing a diff. That's what the walmart-labs patches help with, since obviously a lot of SSR'ed components aren't changing between SSRs, that can be reused, and we can be fast again.
Second, React.js views are more than just banging html together, it also has to call a bunch of functions as part of that process. For example client side sorting, or map/reduce/filter. So if those functions are expensive, your views are slow, even if the html itself isn't all that complex.
Third, since much of our "view rendering" cost is actually computation not directly related to making html, React can't reuse pieces of those computations anyway. You'd need to code your "math" in terms of React components even though there's no html associated with them.
Fourth, if your dataflows are dynamic enough, like a spreadsheet, even if React actually could optimize those computations (which it cant), it wouldn't even be helpful, because while Views are trees, many computations are not. For example, in a spreadsheet: Edit cell C7, quick what is the tree of computations you can skip? The question doesn't even make sense, because spreadsheets aren't trees. Spreadsheets do complicated graph dependency tracking, with cycle analysis and all that, in order to make this fast. React doesn't do that.
As an example of how dynamic Hyperfiddle is, go to http://dustingetzcom2.hyperfiddle.net/ and in the top toolbar click "data" and then click "dev". Dustingetzcom2 is not coded in javascript, its coded in data, and you edit the data live in the dev pane, and the right things update live as you make changes. That's why the render computation is so expensive.
I'm sorry, I'm looking at your example link and you should be getting rendering times in the sub 40ms range. Unless that's not a representative example of course.
Nothing in there seems particularly un-reusable.
Facts are always better. Good news is: I suspect you have no React issue. How is your NODE_ENV? Set to production? After looking at your website, you have no perf issue caused by React itself! Remove the blinking cursor made with setInterval, and use CSS animation for that. You'll see :)
That link has the data points you are looking for, react SSR problems are well understood and documented and have been for some time now, that repo is a year old
also see https://www.reddit.com/r/reactssr/
400m sessions a month doesn't really sound like that much...
[0]: https://github.com/styfle/react-server-example-tsx/blob/4586...
If/when React gets real streaming it will compete better with traditional templating engines, most of which don't do streaming. If you use Node.js and want a traditional templating engine that uses JS template literals and does do streaming, check out my project: https://github.com/matthewp/flora
https://github.com/styfle/react-server-example-tsx/blob/4586...
React definitely needs work here and i think the right people are quite aware of the issues.
The article points out one downside: React's render-to-string faculties are slow.
The other is for performance/seo where the initial markup for the app is generated and served to the client as HTML, then the React app bootstraps on the client and takes over managing the DOM.
1. Initial load using client-side vs server-side rendered. (Server-side should be faster.)
2. Warm load using client-side vs server-side rendered. (Client-side should be faster.)
Comparing to static is interesting, but not really an option if you're serving dynamic content.
Node.js templating engine benchmarks:
https://github.com/marko-js/templating-benchmarks
Framework SSR benchmark (Vue, React, Preact, Rax, Marko):
https://hackernoon.com/server-side-rendering-shootout-with-m...
Not too sure how accurate or biased they are, though.
You might not need SSR. I don't. I expect there will be more work to optimize it and eventually it'll be obviously a good idea. But you don't need it right now if you're working on a SaaS product.
Originally I’d hoped to be able to render a basic version of the page with Rails, then ‘enhance’ it with React - ie render <button>For</button> with Rails, then when React has loaded, replace it with a React component. But I couldn’t find any details on using it this way, and given time constraints choose the simplest option.
What you described is basically `hydrate` which is how to enable React event handlers like onClick after a server-side render.
https://github.com/styfle/react-server-example-tsx/blob/4586...
Start with server-side rendering, and move to React if your application's dynamism demands it. Most applications don't. It's painful to see so many websites building huge, slow, JS-rendered monsters for one or two dynamic elements per page. Unless you are Facebook (and have your JS cached within one hop of every internet POP in the world), server-side rendering is going to yield performance wins for nearly all visitors.
You missed that I'm working on SaaS and a web application. Client-side state is important -- each of my customers can load up most of their state to client-side and the performance is great. This is the whole point of client-side apps. Get rid of all that round trip latency sending HTML to the client of every click. Get rid of your complex server-side framework. Client-side is simpler if you learn and embrace it (and don't need server-side rendering). It's also much easier to have a consistent UX with client-side state.
So use what is appropriate for you use case. For mine, that is 100% client-side no doubt. You can't beat the performance for an application.
I didn't miss that. SaaS means "software as a service", and doesn't imply anything about the complexity of your UI. Plenty of SaaS companies use server-side rendering. Likewise, "web applications" were being written long before React was a thing.
Also no, you don't have to do a full server round-trip for every click, any more than you have to send JSON back to your Reactionary UI for every click.
So sure, if you can truly load all of your data in one big JSON blob and do everything else client side, then I guess you're in the 5% of people who can benefit from React. The other 95% should use a good server-side rendering framework and get things like low latency, URL routing, progressive enhancement and SEO-friendly pages for free, and build the few dynamic elements on their pages with a simpler, more robust technology. I never said that React isn't useful, just that it shouldn't be the default choice for most people.
> build the few dynamic elements on their pages with a simpler, more robust technology
This is a horrible idea that has worked poorly for so many projects. At one potential employer, they did this and their app had a message view with a read count. They didn't care the read count didn't update -- you had to reload the whole page for it to update. Those are the kind of inconsistencies that the above approach encourages because it's not cohesive.
Can you do it? Yes. Should you? No, not in my book.
> low latency, URL routing, progressive enhancement
I've got low latency, I have client-side URL routing, I have no need for progressive enhancement -- it's just more complexity that neither I nor my customers need. These are all great ideas if you have a public website and need to cater to a wide range of visitors. I don't. I'm very happy to be able to only have to support the last couple major versions of each browse.
Again, maybe you're in the 5% of "web application" users that are not actually web applications, but rather, "browser apps that download some data once in a while". If so, great. Most people aren't in that group.
Also, just to clear this up: client side URL routing is not URL routing. It's an ugly hack to make up for the fact that you can't use URLs for their stated purpose. It's honestly sad that we've wandered so far from the norms of the web that URLs have lost their meaning.
So I would ask you at this point to turn this all around. Look at it from my perspective. I've been doing fullstack for more than a decade (professionally, hobbyist for twice as long) so I've done plenty of server-side rendering in frameworks like Ruby on Rails, ASP.net MVC, etc. I've contributed (as lead) to open source gems that have over 800k downloads. So I have invested a lot of time into the server-side.
But today, with client-side, there is a huge simplicity factor. You can only get to it after wading through the turbulent waters of "flavor of the week" client-side projects and noise. But when you do get through that and identify your pillars to build on, this is what you have:
* all of your complexity is on the client-side for web
* you can make a simple fairly clean REST or GraphQL backend that will work with multiple clients (web, mobile, etc)
* for at least REST, you no longer really need things like an ORM on the server-side as all of the endpoints are simple and basically fetching a single data type (I use SQL with PostgreSQL so I would say a table here but it depends on implementation)
* HTTP/2 reduces the cost of small requests so complex things like GraphQL aren't really necessary -- you can stay with REST without a penalty
Is there complexity? Is it different? Does it challenge the conceptions of those used to fullstack? Yes. But there is real value and simplicity here too that you might find if you're willing to put aside your hard and fast rules and try something new.
URLs are addresses of resources on the internet. They're parsed by your browser to request resources on another server.
If you've rewritten this functionality in JavaScript to support storing application state in your single-page application, it may "work well" but it is, in fact, a hack. If you've done this to support storing application state in your web application that sometimes has to actually talk to servers on the web, it's an abomination, and a complete violation of the way web browsers are supposed to work. The fact it is a currently popular hack does not change the nature of the thing. Lots of bad ideas were once popular (remember when everyone wanted to build SPAs in Flash?)
"for at least REST, you no longer really need things like an ORM on the server-side as all of the endpoints are simple and basically fetching a single data type"
If your problem is that you don't want to use an ORM, then don't use an ORM. Likewise, there's nothing stopping you from writing a server-rendered webapp with single-datatype endpoints. You can use HTTP2 with server-side rendering. None of these things are enabled by React.
If these are truly the arguments in favor of a particular client-side stack, it's clearer to me than before why so much of this thick-client stuff is terrible.
https://developer.mozilla.org/en-US/docs/Web/API/History_API
https://html.spec.whatwg.org/multipage/history.html#history
None of these arguments are for a specific stack. React has little to do with any of this. We're talking about underlying technologies that enable the web to be used as a platform for application development.
My point about an ORM is that your API becomes so simple you don't require a lot of complexity that is required with server-side joins of data in order to render a view. That is gone. No need. I'm giving you examples assuming you can extrapolate them to a bigger picture.
"My point about an ORM is that your API becomes so simple you don't require a lot of complexity that is required with server-side joins of data in order to render a view. That is gone. No need."
Yeah, I understood your argument the first time you said it, just couldn't believe you were making the argument. If you don't like joins (related: why do you think you need an ORM to join?), don't write your server-rendered endpoints to use them. The one technology has nothing to do with the other.
That said, as soon as you want to achieve reasonable performance and scale, you will rather quickly find it essential to return multiple pieces of data in a single API call.
However, you are throwing the baby out with the bathwater. Client-side rendering saves server resources, and allows a single API to power web and mobile apps. A pure API is easier to optimize, and is generally a sensible separation of concerns. Of course this doesn't come without overhead, but you don't have to have Facebook-level complexity for this architecture to make sense.
I don't believe I am. There are certainly uses where I openly acknowledge that using a React is a good idea. If you're building something that needs to be a single-page application, for example, then I grant you that concerns of SEO and URLs and whatnot are superfluous. If you have a totally dynamic site, coupled with a Facebook-esque guarantee that your assets are nearly always in the user's cache, and a huge team of front-end engineers to optimize your code, great. But again, that's a tiny minority of teams.
All webpages are "client-side rendered", so that's a bad use of words. That said, JS-based rendering only "saves resources" if you don't count the bandwidth of the user, the amount of code needed to display a page, render speed, time to first render, and so on. I can't count the number of Reactionary sites I visit on a daily basis that hang for 10+ seconds before rendering or peg my CPU -- and nine times out of ten, they're rendering static content. It's an epidemic, caused by people making bad technical decisions, and even big sites like Instagram get it wrong on the regular (Instagram, in particular, pegs my CPU so often while looking at photos that I believe their secret business model is to mine bitcoin in my browser.)
A pure API may be easier to optimize, but unless you've transferred the time you're saving to front-end optimization, I guaranteed that you're punishing your users -- particularly those who are on low-bandwidth connections and/or mobile devices -- with lower performance and higher system demands.
I'd be wary of all of the technical decisions that were made if the decision-maker knew so little about the requirements that they couldn't even call that shot correctly.
Of course, on a long enough time scale, all bets are off.
I've seen it happen more than once. Start with what looks like a straightforward form flow, seems like it should be fine in rails or whatever. Then it turns out some fields depend on other fields, so you've got to dynamically show/hide parts when other parts are set. And doing a server roundtrip, even AJAXey, is just too slow. So you put a bit of client-side Javascript to handle that. And then as the product evolves the interrelations between the form elements become more and more complex and businessey, and you have more and more logic split or duplicated between backend and frontend.
I think generalizing to "we should be building progressive web apps" is harmful. You should do what is appropriate for your use case.
This seriously doesn't mean "no caching" and shows a real lack of understanding about caching.
You state that people should so what is appropriate for use case, though your other comments here go completely against that and are cargo cultist in the extreme. I think perhaps, when you say "should do what is appropriate for your use case" you actually just mean "what I think you should do".
It might be more fruitful to try to explain why I go against that instead of simply saying I do without a rational argument that can be responded to. If anything, the thread pretty clearly revealed someone is extremely biased to server-side web frameworks and is unaware of the progression of client-side web APIs.
I think that the idea of the isomorphic JavaScript app never actually worked in practice. MeteorJS already had a really good go at it.
Sharing JavaScript modules between the client and the server is great but when you start to pretend that the backend and the frontend are the same environment, you're bound to run into all sorts of problems and create inefficiencies.
The kind of performance penalty incurred by server-rendered React is bound to make your system vulnerable to DoS attacks or at best make it unnecessarily expensive to operate.
When programming abstractions shift too far away from the reality of the underlying architecture, you will start paying dearly and the cost won't be worth it in the long run.
In my opinion, the client-server divide is a fundamental aspect of multiuser applications and no amount of abstraction can make it go away.
This still provides what we wanted anyway; the ability for pages to easily be viewable without JS and easily indexed by search engines.
Edit: This PR shows that is likely to be the case. Running in production mode along with some other minor changes shows React running at 88% the speed of Pug. https://github.com/janit/node-templating-benchmark/pull/1
Also, the React component is created on each request instead of just being created once. Unless one's goal is to specifically colour the perception of React, I don't understand that decision alongside the code for Pug which precompiles the template a single time.
(Also declaring the map function outside the component and not creating a closure makes for a tiny extra boost.)
It's disappointing to see that the article took off to this extent given how misleading and inaccurate it is.
Add: on a positive note, this aspect of React is worth benchmarking. Thank you for that.
Max RPS equals number of users you can serve per second. Concurrency should just be tweaked until you eliminate the network latency of your test framework.