Common pitfalls of Single Page Applications & How to handle them
Single Page Applications (SPAs) 🚀 are getting lots of traction. Not only medium but big companies like Facebook, YouTube, Upwork, AWS etc have transitioned from Multi Page Applications (MPAs) to SPAs.
Reason for using SPAs is that they are relatively less complex, can be developed with faster pace, they provide better UX as the application is not reloaded when switching between pages, and also re-usability is one of the major benefits as these SPA frameworks are component-based.
However they are some downsides with using SPA frameworks, and fortunately there are people out there, constantly working to overcome these issues with Single Page Applications.
Let’s look at some of the issues one by one and how they can be handled
1. Search Engine Optimization (SEO)
There is a generalized opinion about Single Page Applications that they don’t scale well when it comes to SEO. As we know SPAs are downloaded once on the client side and views are defined on client side i.e. they don’t have unique URL addresses. Now that’s not the case with every search engine because Google Bots can crawl a SPA and index the pages accordingly, however they are some caveats to it.
What if you want to develop your next website with SPA framework and need SEO at the same time. It’s not that difficult to achieve as some of the frameworks support SSR, and offer solutions for SSR out of the box.
You can read the details in the links shared below:
Most of the developers coming from either classic web development background or who have used jQuery in one of their projects are gonna go for jQuery for manipulating the DOM, running an AJAX request etc. This might seem a straight forward approach but in Single Page Application world jQuery is considered as an anti-pattern.
I am not going to discuss about jQuery’s disadvantages, as jQuery is the reason modern browsers have evolved. But everything jQuery offers is either supported by these modern browsers by default or is available as a plugin on NPM.
For example using fetch instead of $.ajax which comes pre-packaged within modern browser or axios npm library which allows cancellation of request as well and is pretty light weight.
Let’s be honest all things must end and unless you have to support very old browser there is no point in using it for modern browsers. These APIs that are being offered by the browser are free, no extra script load means faster load times too.
3. CSS & JS bundles
As our application size grows so does the size of JS and CSS files, loading such an application will take time, minification & concatenation of CSS and JS bundles will help in reducing the size of these assets significantly.
Since Single Page Application are fast paced and changes are being incorporated rapidly, it demands refreshing of the assets on the server as soon as they are deployed. Different applications use different caching strategies which helps when users re-visits the application the assets are loaded from the cache saving a lot of time and bandwidth for the user. But caching these assets pose another problem i.e. if there’s bug in your JS and you’ve pushed the fixed, it might not get to the client even after deployment as cached version is being presented to the user by the browser. To handle this one must use Hashed Naming of assets that helps in Cache Busting. For example instead of naming your app.bundle.js you can name it app.[hash].bundle.js and keep changing the hash value every time you make a new build, bundlers like Webpack provide these strategy out of the box, so you really don’t have to do anything yourself.
Analytics in Multi Page Applications is easier and page views are tracked by default. Single Page Applications doesn’t have physical pages like Multi Page Applications, so keeping track of virtual page navigation has to be notified via application itself.
5. Lazy Loading
So it’s not only the static bundles that adds to the size of application but also the app code that has components, services, modules etc. which is included in the final bundle of the application. SPA frameworks supports on-demand loading generally known as lazy loading. Unlike a Non Lazy Loaded application which has single file that contains all the code for the components in the application.
Lazy loaded app has separate files for each module and only gets downloaded when a request is initiated from the browser, which takes place normally when the user visits the route responsible for loading the module/component.
Routing is a way to navigate back & forth between pages of your application.
There 2 types of routing strategies
a. Hash Based Routing:
As the name suggests there is a hash(#) included in the URL that helps in simulating different views of application.
The part after the hash (/user/1) is only client side and no reload happens when this part changes. Since the manipulation of the routes takes place completely on the client side inside JS script, to enable browser go back and forth in the history needs be handled manually on the client side which off course requires some work.
b. Push State Routing:
There is a new HTML5 history API which is used for manipulating the history of the application history stack. We have for example window.history.back() for moving a step back or window.history.forward() to step forward. There are a lot of methods which this API provides out of the box. And is really awesome, but it comes with it’s own challenges.
Let’s analyze a URL
www.example.com when users type this in their browser it returns
index.html and site loads perfectly. Now the user navigates to
www.example.com/user/1 and brings up the view with details of user 1. The problem with this is if the user reloads the website the server is going to look for
www.example.com/user/1/index.html which doesn’t exist. As browser returns index.html for
www.example.com only, which is the root. And a 404 for
www.example.com/user/1 because user/1 directory doesn’t exist on the server and thus doesn’t have an index.html of it’s own.
To handle this issue what you have to do is return
index.html for all the incoming request to the server. It will not return 404 for
This solves our problem but it will return index.html for a non-existent route in the application. You can either live with it or add custom handling of routes on the server e.g. add configuration for the routes in the APACHE etc, it’s an ugly way but does the trick.
Key take away from this article is that SPA frameworks like any other framework whether Backend or Frontend comes with its own challenges. But those problems are never going to stay there forever as they are always developer out there, working on finding solutions for these kind of issues.
— That’s all folks. Thanks for reading. 🎉
If you have any suggestions or comments, drop it below the article.