6 ms·
We improved React loading times with Next.js
- joshuakgoldberg 4y agoI'm so excited about this . It's a testament to how well-built-up modern frontend tooling is, especially around React. The things that used to take hundreds or even thousands of lines of config can now be done in a few dozen at most with managed libraries. And better!
- maigret 4y agoUnfortunately too much JS has made the web slower, check this https://www.speedcurve.com/blog/web-performance-page-bloat/ https://www.speedcurve.com/blog/web-performance-page-bloat/ for a quick view or infrequently.org for longer explanations. React starts to be dated now and there are leaner alternatives offering most of the functional advantages, like Svelte or Lit. The tooling evolves indeed and I hope it gets again nearer to the browsers, thanks to web components, better CSS (hello variables), WASM and much more.
- adchurch 4y agoI'm one of the engineers that worked on this - would love to hear any thoughts or feedback anyone has! How does your team deploy your Next.js frontend?
- bgirard 4y agoI'm curious where the majority of the win came from? Do you have a before & after trace handy to compare what changed? Looks like you opted not to use SSR, which I think is a good choice for smaller teams. CSS changes are unlikely to account for a large performance win. Did you use a CDN before? Perhaps the biggest win was moving to a better CDN + built-in preloading/prefetching provided by NextJS?
- adchurch 4y ago> I'm curious where the majority of the win came from? Great question! The boost can be explained by JS vs. raw HTML+CSS performance. In the past, we sent a dummy loading screen but we then had to download tons of JS + run that to even show a "real" loading screen (i.e. page-specific loading screen). Now, the HTML response (which you can inspect yourself, `curl https://my.causal.app https://my.causal.app`) already has a skeleton of the page, which doesn't need any JS to download and run before showing the "real" loading screen. The UX is better because users spend noticeably less time staring at a blank screen and there's much less layout shift too!
- bgirard 4y agoWhich metric improved by 70%? Time to show the skeleton? I agree the skeleton is quite good. I see it takes about 350ms to show the skeleton and about 1s to show my content.
- adchurch 4y agoYep - the metric was First Contentful Paint, which is basically the time-to-skeleton in our case :)
- JayStavis 4y ago> backend API calls will be very fast because of colocation on GCP Any chance you guys measured this speed difference? Was there a path considered to locally cache api responses on the vercel server or in middleware somewhere? Trying to reason about a similar decision right now. There's probably a simple way to cache hot backend request/responses to get static-like speeds?
- adchurch 4y ago> Any chance you guys measured this speed difference? No, but we actually can get some comparison, since as I mentioned we host preview apps on Vercel! I did some quick tests right now, and it looks like based on logs, the API request to our Node backend takes: - From Vercel: ~300ms worst case, ~40ms best case - From within GCP: ~120ms worst case, ~20ms best case These numbers are very approximate, but hopefully still insightful! And I'm not sure about the cause of the variance, there are quite a few links in the chain that could be at fault. > Was there a path considered to locally cache api responses on the vercel server or in middleware somewhere? We do cache the responses using a CDN; adding another layer of caching beyond this wouldn't help much since at that point we need to fetch fresh results anyway. > There's probably a simple way to cache hot backend request/responses to get static-like speeds? Yes, the CDN cache I mentioned is almost instant in good conditions (~2ms on my internet connection) - the problem is sometimes you do actually need updated data, and having huge variance between the cached response speed and the uncached response speed could be undesirable for users.
- JayStavis 4y agothanks for those figures! It makes sense on the cache invalidation given the type of content Casual is serving. It will be interesting once Vercel offers colo'd data sources and more with their edge rendering, which they just announced: https://vercel.com/blog/regional-execution-for-ultra-low-latency-rendering-at-the-edge https://vercel.com/blog/regional-execution-for-ultra-low-lat...
- styfle 4y agoISR will give you static-like speeds https://vercel.com/docs/concepts/incremental-static-regeneration/overview https://vercel.com/docs/concepts/incremental-static-regenera...
- throwaway4good 4y agoWhat does next.js offer if server side rendering is of no relevance? It seems to me that ssr adds a lot of complexity and a great number of projects have no need for it at all.
- manigandham 4y agoThat’s literally what the article is explaining. Better routing system, and bundling, and a simpler optimized config for output.
- throwaway4good 4y agoBut that is a lot of complexity and dead functionality to drag into a project for just that? Surely next.js's router is not that different from React router.
- adchurch 4y agoIn our experience, using Next.js reduced our complexity, because it has out-of-the-box implementations (and simple configuration) for lots of stuff we had to manually hack around with CRA as our project grew
- Scarbutt 4y agonextjs is crap but IMO doing react ssr on most requests with hydration is faster, more robust and less complex than going full csr/spa.
- selfmodruntime 4y agoWell true SSR allows you to send zero javascript to your client, so this is ultimately a net positive. My site is written entirely in React because I like working with it, but thanks to Next.js you as a client will never know the difference between that and me serving static HTML in the first place. All pages, subpages and blog posts ship in a relatively tiny 200KB bundle.
- 4y ago
- gatvol 4y agoSsr to improve a static app performance? Sounds like madness to me. More complexity plus much larger surface to secure.
- adchurch 4y agoOne nice thing about Next.js is you don't need to use SSR unless absolutely necessary - it will statically generate all your pages by default (which is similar to but not the same as SSR - it runs once at build time rather than on every single request), so the result is similar to CRA but with quicker first page load times and a much better developer experience. But you have the power to use SSR where necessary too, which is not really possible with CRA (without unscalable hacks).
- pitnikola 4y agoGreat stuff — thanks for the write-up! Do you mind sharing the Dockerfile you use for deploying?
- jsnk 4y agoWhat cause the performance improvement? Maybe I missed this detail. I couldn't find anything on why the performance improvement happened when they moved from CRA to Nextjs
- adchurch 4y agoI explained it a bit more here: https://news.ycombinator.com/item?id=33319806 https://news.ycombinator.com/item?id=33319806 Let me know if this still doesn't answer your question though!
- subpixel 4y agoI've been checked-out of the SSG world for a couple years and am now evaluating different tools and frameworks for a project at work. I'm intrigued by the direction being taken by Remix, which posits that today's backend options are so improved compared to those of the recent past that they (arguably) have eroded the utility of a static site, period. https://remix.run/blog/remix-vs-next https://remix.run/blog/remix-vs-next When it's not crazy difficult or expensive to have a very fast app _and_ database close to your users, you don't have to architect around that deficiency, which is what SSGs are designed to do.
- crooked-v 4y agoThough it's worth keeping in mind that Next's next big structural update [1] is pretty much an attempt to assimilate some of the basic concepts of Remix wholesale. [1]: https://nextjs.org/blog/layouts-rfc https://nextjs.org/blog/layouts-rfc
- leerob 4y agoNot exactly – this has been in discussion for many years. From the post: > Some routing conventions were inspired by the Relay-based router at Meta, where some features of Server Components were originally developed, as well as client-side routers like React Router and Ember.js. The layout.js file convention was inspired by the work done in SvelteKit. No doubt React Router has certainly impacted the entire React ecosystem, though!
- subpixel 4y agoInteresting. Ultimately neither one of these companies stand to make money selling a web framework, but one of them happens to have a business for which it makes sense to commoditize and control its complements. Put another way: Remix may have underestimated the value Next represents to Vercel.
- byhemechi 4y agoremix comes with the main caveat that if your API is slow or very far away you will end up with a slow frontend, whereas next.js prerenders pages meaning they're always going to be fast. obviously this doesn't matter that much if you're making a customer dashboard but if you want to have public facing data and your backend isn't globally replicated you are either going to have to implement your own caching layer or your users are going to have a bad time
- pferdone 4y agoI mean good for them for improving their user‘s experience. I am just surprised that maintaining your own webpack config seems like such challenge. Enabling chunks to split code to improve loading times or dynamic imports, it‘s not exactly rocket science. Yes DX and all improved as well, but CRA is such a bad choice for production code. It gets you going fast(er), but as soon as you have to tweak it, it seems like devs jump to the "next" framework that already has those tweaks builtin…until they hit the next roadblock. Thus you never learn what actually makes it all work.
- adchurch 4y agoImo it's a question of prioritization - time spent fiddling with a Webpack config is time that could have been spent on something that will more immediately benefit a user. That's the big advantage we saw for switching to Next.js, which handles this and many other details for us, without the confusing & brittle hacks that had accumulated in our CRA setup. > Thus you never learn what actually makes it all work. I agree this is unsatisfying - however it's a problem no matter what! We have to live at some level of abstraction in order to make any forward progress. There can still be lots of learning along the way!
- mikojan 4y agoThe problems described in the "Routing" section are trivially automated. You do not even need a separate data loading library because react-router-dom ships one. The problems described in the "Styles" section would have been solved by migrating to a modern bundler: vite.
- adchurch 4y ago> The problems described in the "Routing" section are trivially automated. You do not even need a separate data loading library because react-router-dom ships one. I'm not sure which problems you mean; fwiw the routing section is more intended to explain how we migrated `react-router`-style routing to `next/router`-style routing :) > The problems described in the "Styles" section would have been solved by migrating to a modern bundler: vite. I think the problems with impure styles (e.g. `styles/button.scss` referenced in the post) would have been an issue no matter what bundler we used, right? Which problems are you referring to?