A Bit of History
We never considered writing a whole application like that however; navigation still fetched a brand new page from the server, causing a full reload. There were still multiple
Are we now ready to see SPAs replace traditional server side rendered (SSR) apps wholesale?
Short answer: no, but…
Longer answer: read on Macduff.
You Broke the Web!
It’s fair to say, there are still those that don’t love the idea of SPAs.
Check out the film here.
Let’s take some of these concerns one by one and see where the current SPAs land.
- Caching. The JS is a static file and can be easily cached by the browser. This drastically reduces the subsequent load times as the file no longer needs to be fetched.
- CDNs. Use of static assets like this is one of the big benefits of a SPA; they can be loaded from CDNs closer to the edge of the internet where content is accessed from.
/admin/*URLs, so why send it to everyone? Angular has been doing this route splitting for a while, Ember is close, and React has the functionality. Though true to React’s slim nature, the developer needs to wire it up themselves, so it comes at the cost of a significantly greater effort.
- Server Side Render, and then inflate the SPA. All of the major SPA frameworks now offer the functionality to handle the initial request on the server and return a pre-rendered page to the client, while in the background loading in and inflating the application state into the SPA. In many ways this is the best of both worlds, but right now comes with significant development overhead for applications with real-world complexity.
In summary, the first load time can be significantly improved from the ‘out of the box’ experience by investment of developer time.
Critique: More developer time? Meaning SPAs are more expensive to develop. If you consider the fact that you’re having to represent your entity structure on the client and the server, include validation code in both places, and manage permissions and security in both places, then it’s looking a lot more expensive.
Response: It’s expensive in different places. Yes, entities are often described in both places, but this is relatively trivial. Validations can be handled solely on the server-side under many circumstances, and permissions only need to control what the application shows – all the real security has to remain on the server. The fact remains however, that if you simply replace the server rendered pages with an API and add on an SPA, then the development costs are likely to be higher.
Critique: SPAs may offer some improvements, but they create brand new problems. The ‘back’ button remains broken. New pages render half-scrolled, or the new URL appears a second or two before the content loads.
Response: If you write the SPAs in a best-practice fashion, then very few of these issues should be apparent. Which doesn’t change the fact that in an SSR app, these issues just don’t appear at all.
The truth here is that SPAs are a different technology, and different technologies surface different problems. At this point, SSR apps have been mature for nearly 25 years, whereas SPA frameworks are not even a decade old. That immaturity means that not all the kinks are ironed out, but the signs are that they will be.
Critique: Kinks like accessibility? SPAs typically have terrible a11y, a-tags without
href properties, deeply nested mark-up, and no indication to screen readers when the content has changed.
Response: Screen readers often rely on the traditional “request page / reload with new content” paradigm of SSR apps to know that content on screen has changed. The navigation approach of SPAs, which simply changes the URL and injects new content, does not provide enough hooks for screen readers to work from.
On one hand, screen readers are going to have to adapt. Even within SSR apps, there’s enough interactivity in today’s web apps that requires them to know when content is updating outside of a full page load. On the other hand, SPAs should do more. All the major frameworks have fairly easy add-on modules that support an improved screen reader experience, and in 2020 Ember is focussing on improved a11y by default.
Single Page Apps – The Application for your OS
Many of the SPA concerns can be addressed with a little extra effort. That’s the cost, so let’s take a look at the benefit – what is it that SPAs offer that SSR apps cannot? What is it that makes them a preferred choice?
The paradigm of how you build an app is changing
In the days of SSR apps, we’d write a monolith server, responding to all requests a user made with the appropriately rendered HTML page. When we started to switch over to SPAs, we replaced the HTML rendering views with JSON rendering APIs – but the fundamental server architecture was the same.
That model still persists, and is still the predominant way we write apps at Media Suite for a number of reasons, but times are changing.
Functionality is becoming more and more commoditised as Cloud Services step in and replace commonly required features. For example, we could use Google Firebase for data persistence and authentication, Stripe for payments, Raygun for crash reporting, AWS Lambda functions for custom API end-points, Google Maps for geospatial data, OMDb for movie information… If the apps of the future are more likely to be composed together from these various cloud services, then the SPA is perfectly poised to be a hub in the middle.
Sure, you could write a server rendered app that pulled from all these sources, but why would you? SPAs can do the same job and be served from any CDN static hosting source easily and cheaply. By using an SPA under these circumstances, the cost of your hosting drops, integrations are easier and you’re using the right tool for the job.
The jury is out whether these ‘composable, commoditised services’ will provide the necessary coherent experience for the significant and complex applications that make up the lion’s share of custom software development. Right now, I don’t believe they do. But I do believe we’re on a tipping point, and we’ll gradually see our services get smaller and more focussed, to be composed together via SPAs.
The ability to work offline
The poster-child feature of SPAs is that they can really make the most of the offline APIs available through all modern browsers. Try to save while offline? No problem, save to a local cache and allow the user to keep using the application. When next online, the user can synchronise and resolve any conflicts that may have arisen.
The only real technical impediment to this functionality is the browsers’ inconsistency in dealing with how much storage space to make available to the web application; it can make saving large numbers of media files a little fraught. Yet we don’t all build offline as a matter of course, because it just isn’t a high enough priority to spend our development budget on it for many apps. As patterns and libraries continue to improve, the hope is that adding offline becomes a cheaper and easier proposition.
Better handling of loading and error states
Ever seen pages like this?
These are known as ‘skeleton screens’ and can be used as a placeholder while content is loading. It gives the user a nice sensation of what to expect, and significantly improves the perception of page-load performance over waiting for a blank screen to fully render.
Having control over what is displayed during the loading state is a powerful weapon in the war with user engagement. Skeleton screens are one tactic, but there are others that can be more appropriate for specific scenarios.
Error states are also well accounted for. If part of the data fetch fails, then this can be handled far more gracefully than returning an error page. SPAs can determine the behaviour they want – they could attempt another fetch, return data from a previously cached version, or provide the user with a simple alert. Most strategies are also available on an SSR app, but are actually more difficult to implement. With the clean SPA/API interface, there is one place to handle failures.
Animations as a first class citizen
Imagine something like this:
This is a lovely UI pattern for log-in and registration, and you could do this in an SPA or SSR. However, if you wanted the URL to also change from
/register when the user pressed the “SIGN UP” button, then with an SSR you’re out of luck. The page will need to reload.
With SPAs, not only can we create awesome animations, but we can do them across route boundaries. This allows context to move from one page to the next, helping the user understand the interactions that are taking place. It’s what mobile apps give us, but better, because the URL is the key piece of information that unlocks people being able to share their favourite bits of the web with each other.
The browser as an application platform
Java Applets had tried this in the late 90s. The Java runtime was heavy, had versioning issues and was an ongoing security nightmare, but… they actually felt like fixable issues. The key problem however was that it just wasn’t the web. It was another technology bolted onto the side. As the web grew in power and capability, Java Applets fell away.
These are easy bets to make, because they’re already happening.
Jonathan is Director of Software Development at Media Suite.