You Should Not SPA
Tags: webdev, webperf, html, a11y
Published: 2020-06-06 13:43:51

As a warning before reading: this post is not being backed up with tons of research and is based more on experience.

Single Page Apps have become the thing to do in the past few years. Many frameworks and libraries have evolved to support this idea as tools such as React make it fairly easy to get you up and running. And if you give everything a push you can make your site load only just the JavaScript it needs to load and only the CSS it needs for a particular page, and even just the minimum amount of data via API it needs to display a page. So cool and awesome!

However when doing SPA you soon notice you're doing all sorts of extra development you never had to do before, and you're also probably NOT doing things you **should** be doing.

## "It can't go wrong!"

One of the easiest things to point out that everybody encounters is the scrolling of a page: hit that back button and restore the position, as well as going to the proper location when going back forward. Easy enough, huh? Still, extra logic you are unlikely to need with traditional HTML page transitions.

Much more easy to miss is the fact that you should also manage where focus goes. You see, traditional HTML page transitions automatically move focus back to the beginning of a page. With SPA when you click a thing and go somewhere you can't really tell what happens with focus. This is a problem for users of screen readers, and they may easily get lost.

Sure, you could go ahead and fix that too, just do the same as with scrolling! Focus the first element each time a new page is loaded and then... oh. Should the focus be restored to where it was when moving in history or should it go back to the first element? That is already a lot of extra headache and it gets worse and worse the more you notice things that browsers normally do that no longer happen with SPA.

Another common issue on SPA sites is how stuff on page loads in chunks. Ever scrolled a page to content when suddenly the thing you read is pushed further down as more things are loaded? This can happen with traditional sites too, but is far more common of an issue with SPA sites. Programmers just don't seem to know to care about keeping their layout integrity.

## You do things twice

Routing. Raise your hand up if you have two routers: one on the server side, and another that works universally for server and client. The server side knows more and has additional meta for caching and has indexing rules for robots (search engines), while the universal one probably does not. You may even have the exact same routes defined individually for both, which can easily result into debugging for a while until you remember you forgot to add the another.

Then you have situations where you have developed a feature and a page has worked perfectly fine, until your error monitors jump right up and you're like why, I tested this thoroughly! Then you notice you forgot to actually click to the page via a SPA link, page did not load all the data, and that is why you get errors. Sure, this issue can be avoided with well made architecture, but you still need to have the knowledge to do it right.

That also brings up another issue: you need to add a test for two cases for each and every page you make. One for traditional HTML page load, and another one where user comes to the page via a SPA link. While somewhat straightforward a thing to do once you've done it once, it is still extra work you need to do every time you develop for SPA.

Lazy loading JS and CSS is another trend that has been going on alongside the SPA one. You want modular efficient loading of just what you need, and the way to achieve that is by adding lazy loading support for both JS and CSS. Setting this up for both development and production is quite a bit of work, and can take a good bit of time until you get it to work just right. Especially the dev side can be unbearably slow if you add support for these two into an existing large codebase.

## Dev time spent on optimizing performance and a11y is harder on SPA

With traditional server-rendered pages you can easily optimize JavaScript and CSS page-by-page by adding in only the features you need on each page. This can be done manually and while it requires some thought and process to maintain unified file structure it is still a lot less work than what you have in the code splitted SPA side of things.

This also leaves more time to consider other things, such as "can this page work well enough even without JavaScript?" - when living in the SPA world you have already so many things to consider you simply don't have the time for no-JS. Besides, it is very likely you're so dependent on JS on a SPA site that seeing anything relevant on the page with JS disabled is unlikely.

Then we have the side of accessibility. It is hard to get right even without SPA, but when SPA is added into the mix you're begging for trouble.

## Why people do SPAs?

I'll go straight for the answer: because it is a challenge and people like to do hard things. Or you actually need it for your rich UI experience. Say, Trello is a great example of a software that only works as a SPA. However, your common news, weather, or e-commerce site probably shouldn't be written as a SPA no matter how cool that is.

Going for a SPA can be seen as a solution for performance issues as you get this false thinking that you'd then only be loading only the stuff you need instead of full HTML pages, but the ugly truth is that the problem is a single monolith JavaScript. For that SPA is just a workaround to allow for code splitting, and better perf and reduced traffic. Yet it is not a silver bullet: it is likely a very big job to get that ex-monolith to eventually be tiny and lean enough to be anywhere close to a scriptless or lightly scripted page.

Generally you're likely to be better off by reducing the amount of JavaScript and splitting scripts manually, or make your site have multiple bootstrappable mini-apps and automate how these are loaded on generated HTML pages.

## Endings

You can probably see that I'm not convinced of SPA and that I've worked with a codebase that, for the most part, shouldn't work as a SPA. I hope there is some informative value here despite all of this being just a throw-away directly from my head.