SPAs and React: You Don’t Always Need Server-Side Rendering
As you may have noticed, the Start a New React Project section of the React docs no longer recommends using CRA (Create React App). Create React App used to be the go-to approach for building React applications; (that only required client-side routing and page rendering). Now, however, the React docs suggest picking one of the popular React-powered frameworks that support server-side rendering (SSR).
I’ve built applications with everything you’ll see on that list of “production-grade React frameworks,” but I also spent many years building SPAs (Single Page Applications) that only needed client-side functionality — and everything was fine.
Whilst there are many applications that do need server-side rendering, there are also many applications that don’t. By opting to choose an SSR React framework, you might be creating problems rather than solving them.
What Is an SPA?
As the acronym suggests, an SPA only has a single page. An SPA might have navigation, but when you click from “page” to “page” what you’re experiencing are routes, not pages. When you navigate to a new route, React takes over and hydrates the “page” with HTML and (usually) data that has been sourced using a client-side HTTP request.
What Is SSR?
SSR applications are different. Server-side rendered applications actually do have pages. The data is sourced on the server, where the page is compiled, and then the final output is sent to the browser as a complete HTML webpage.
As noted, with SSR you need a server — and usually this will involve a cloud provider. If your SSR framework only really works with one cloud provider, you might end up experiencing vendor lock-in. Thankfully frameworks like Remix and Astro are “server agnostic,” so you can either bring your own server, or use an adapter to enable SSR in your cloud provider of choice.
What Are the Problems with SPAs?
One problem that crops up again and again is “spinner-geddon”; where each time you navigate to a new “page,” you’re presented with a spinner animation to indicate that data is being requested, and only after a successful HTTP request completes will the page become hydrated with content.
An SPA isn’t great for SEO (Search Engine Optimization) either, because as far as Google is concerned, the page is blank. When Google crawls a webpage, it doesn’t wait for HTTP requests to complete, it just looks at the content/HTML in the page, and if there’s no HTML then how can Google rank the page?
Because of this (and a number of other reasons), there has been a shift in React application development towards server-side rendering. But, whilst both of the above sound like considerable problems… are they, really?
The classic developer response will likely be: It depends. And it really does! I’ll now tell you a short story about an SPA I built a few years ago, so you can judge for yourselves.
A Perfectly Acceptable Use for an SPA
Rewind the clock to 2018, I’d been hired by a “tech consultancy” company that had been brought in to perform a “digital transformation” for a large financial institution based in London.
My first project was to build a browser-based solution that would replace an antiquated piece of licensed software that was no longer fulfilling its duties, not to mention costing the company money. The application was for internal use only and would only ever have three users: Margaret, Celia and Evelyn, a delightful team of people who were nearing retirement age, but who played an important role in the firm.
The application I built took approximately eight weeks to complete, only used client-side HTTP requests to fetch data from an API, had authentication, was deployed using an existing Azure DevOps pipeline, and wasn’t Search Engine Optimized.
Margaret, Celia and Evelyn absolutely loved it, and they didn’t mind the occasional spinner — since the app solved a problem for them. It also solved a problem for the firm: no more expensive software licensing. I have it on good authority that it’s still in use today. I also happen to know that Margaret, Celia and Evelyn have all since retired, in case you were wondering.
Are SPAs Still Relevant?
I think they are. There are many internal applications that will never see the outside world and won’t need to use any of the features that come with the more modern React-powered SSR frameworks. But since the React docs are no longer recommending CRA, what else could you use if you were building an SPA today?
Using Vite with React
Vite can be used alongside React and steps in as a more modern replacement to Webpack (the module bundler used by CRA).
“Vite is a build tool that aims to provide a faster and leaner development experience for modern web projects.”
I thought about turning this into a tutorial, but there’s really no point.
The Vite docs cover everything you’ll need to know in the Scaffolding Your First Vite Project section; and choosing from the CLI prompts, you’ll have a React app up and running in about ~20 seconds.
You’ll also see from the image above, Vite isn’t only a great choice for building React applications, it’s also suitable for use with other frameworks.
What Are the Key Benefits of Using Vite?
In short, bundling.
Bundling occurs whenever a file is saved (which happens hundreds of thousands of times during the course of development). With tools like Webpack, bundles have to be “torn down” and rebuilt to reflect the changes. Only after this bundling step is complete will the browser refresh, which in turn allows developers to actually see their changes.
With Vite, when a file is “saved”, only the module that changed is updated in the bundle. This results in a much faster bundling step and a much more productive and pleasant development experience.
There are a number of other benefits to using Vite, which have been clearly explained in the docs: Why Vite.
So there you have it, out with the old and in with the new…but, the legacy of the React SPA can live on!
Naturally, there are many cases where an SPA isn’t the most suitable choice. However, when it comes to SPA or SSR, it’s not “either-or” — it’s “both-and”.