If there were a Hippocratic oath for web developers, it would surely include a promise that any modification to a web page will provide a net improvement to User Experience.
And yet, there are many sites that have multi-megabyte code bundles, break native browser features like page history or make users wait too long before showing page content. Most often the root cause of these infractions is a poor or unnecessary implementation of the single-page application (SPA) architecture.
In this article, we’ll look at how SPAs are designed and the common pitfalls that detract from user experience.
Single-page application architecture
Most websites are broken up into pages in order to make the information they contain easier to consume. The traditional architecture is to give each page a unique URL. To navigate to a page, the browser sends a GET request to the page’s URL. The server will send back the page and the browser will unload the existing page and load the new one.
For the average internet connection, the navigation process will likely take a few seconds, during which the user must wait for the new page to load.
From a user’s perspective, such a website would appear to have pages just like any other, but from a technical perspective, this site really only has one page. Hence the name, single-page application.
Routers will typically include functionality to:
- Handle navigation actions from within the page
- Match parts of the application to URLs
- Manage the address bar
- Manage the browser history
- Manage scrollbar behaviour
The intention of the single-page application architecture is to improve UX, and it does so in the following ways:
Ironically, single-page applications can harm UX if certain pitfalls aren’t avoided:
history.pushState. Most good router libraries will help you do this, but there will still be some manual implementation required.
SPAs have a large initial download size. Since the router and multi-purpose page elements must be downloaded first for the app to work, SPAs require an upfront download before they run. Build tools like Webpack can help by lazy-loading any code not needed before the first render.
SPAs will need custom loading states and errors messages. Browsers give visual cues that a page is being loaded, and a web server can return a 404 page. The result of an AJAX request, on the other hand, is hidden from the user by design. SPAs must find a way to let users know if the app has successfully responded to their actions or not.
The purpose of the SPA architecture is to provide superior user experience, but unless proper care is taken, it can have the opposite effect!
Here are the key things to keep in mind if you choose the SPA archteicture:
- Configure your router software so native navigation features aren’t broken
- Employ build tool features like code-splitting and lazy-loading to ensure the initial code bundle isn’t too big
- Implement loading states and error messages so that the user knows the page is responding to their actions
- Use prerendering or server-side rendering to ensure your SPA shows content as early as possible
Above all, make sure you have budgeted for the extra work required for building, testing and maintaining an SPA.