SSR doesn’t add too much complexity and at the very least is a reliable way to serve a server-rendered shell of the application so the content doesn’t fly about as it loads.
I still write static HTML if I'm positive it'll be a forever fit - but anything client facing or with an ambiguous feature I reach for Next.
(Seems like the folks in the article are beginning to use SSR, and have some great use cases with publicly available, SEO-friendly content, but a lot of apps don't, and can benefit from avoiding the operational complexity.)
Create React App is a bit long in the tooth these days, so I can imagine `next export` being a lot nicer to work with in a whole bunch of ways, but the only advantage of `next export` I can think of over something more modern like Vite is file-system routing.
For those using `next export` but have also evaluated Vite, is FS routing what made you choose `next export`? Or is it something else?
Disclaimer: Asking with ulterior motives. I'm building https://reflame.app, a Vercel competitor focused on client-rendered React apps, with millisecond deploy times to previews and production. We currently have decent compatibility with Vite and CRA, but considering if we should try to add support for apps using `next export` as well.
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?
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`) 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!
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?
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.
https://vercel.com/docs/concepts/incremental-static-regenera...
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
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.
> 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!
Put another way: Remix may have underestimated the value Next represents to Vercel.
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.
But you have the power to use SSR where necessary too, which is not really possible with CRA (without unscalable hacks).
> 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!
The problems described in the "Styles" section would have been solved by migrating to a modern bundler: vite.
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?
Maybe I missed this detail. I couldn't find anything on why the performance improvement happened when they moved from CRA to Nextjs
Let me know if this still doesn't answer your question though!