Why Progressive Web Applications Are Not Single Page Applications
For some reason many think progressive web applications (PWA) are single page application (SPA).
This is wrong, very wrong.
A SPA can be a PWA, but a PWA does not have to be a SPA.
I recommend against being a single page application for sites targeting organic search traffic and for most online solutions.
Because SPAs don't provide the better user experience developers think they do. In fact, they create a relatively poor user experience in most cases. And no, your developers probably are not the exception that makes good SPA user experiences.
Requirements to be a single page application are not the same requirements to be a progressive web app. This means you can make a SPA, but it is not a PWA and vice versa.
So why do so many developers and marketers assume a progressive web application is a single page application?
Could the Google Chrome Team be the cause of this confusion?
And, what is the best type of website for a PWA?
- What is a Single Page Application
- Why Progressive Web Apps Kill Single Page Apps
- Why Progressive Web Apps are not Single Page Apps
- Why the Chrome Team May Have Created PWA is a SPA Misconception
- My Recommended Progressive Web Application Website Model
- Wrapping It Up
What is a Single Page Application
The primary draw many of us had to use single page applications was the desire to build websites to feel more like native applications.
Without the traditional round trip between the browser and the server for the entire page the app shell remains visible in the browser while the content is being retrieved and rendered.
In other words, server-side rendering is moved to the client.
Instead of retrieving full pages either partial pages or just data is retrieved using a network call behind the scene. This has been done using AJAX, but today has changed to 'fetch'.
The primary page is the 'app shell', or the minimal amount of markup to compose what we refer to as the application chrome. This typically means the layout's header, footer and primary navigation.
Popular examples are Angular and React, but there are several others that either failed to garner mass popularity or are currently emerging. There has probably been a new one released as I wrote this article!
I call them fast food frameworks because they are full of over processed code and syntatic sugar with a lack of technical nutrients. Just like actual fast food is full of processed carbs and sugar that makes many of us obese!
This perceived convenience and cushion of excessive code makes these frameworks an irresistible force to most developers.
But the choice of these frameworks comes at a cost and that is paid in poor user experience and reduced customer engagement or productivity.
Back to the main point, Single Page Apps can be Progressive Web Apps, but PWAs do not have to be SPAs.
That's because a single page app does not require a service worker, web manifest file or being served via HTTPS. They also fall short in the spirit of progressive web apps where the ultimate goal is to deliver amazing user experiences.
Why Progressive Web Apps are not Single Page Apps
Progressive Web Applications are websites that meet three technical requirements:
- Served using HTTPS (Secure)
- Have a Valid Web Manifest File with a Minimal Set of Icons
- Register a Service Worker with a Fetch Event Handler and Minimal Offline Support
No where in those requirements does it say the PWA should not request server rendered pages or that content must be rendered in the browser.
There are some user experience expectations progressive web applications have, such as speed, engaging and integrated. These are measured more in the eye of the beholder, but again nothing about client-side rendering.
As progressive web applications grow in demand developers naturally want to retain their love of single page applications, even when they are no longer needed.
Wait, did I say single page applications are no longer needed?
Let's dive into this juicy position.
Why Progressive Web Apps Kill Single Page Apps
Several years ago I was anxiously awaiting my first presentation at O'Reilly's Velocity on building fast single page applications watching Patrick Meenan demonstrate service workers. As I watched Patrick I could not help but think everything I was about to show was a polyfil.
I was blown away by this new web platform feature, service workers, because I could see how I architected my single page applications now as a native or built-in browser feature!
I architected my single page applications differently than Angular and React have designed their application structures. My architecture was built with user experience the primary feature requirement. Fast food frameworks are designed to make the developer experience the primary goal.
So how do PWAs kill SPAs?
A properly designed progressive web application pre-caches many site assets: scripts, css, images and markup, before they are required. This eliminates the network from the rendering process and enables the application to work offline.
A PWA can still use the app shell model, but now instead of the core markup being rendering in the UI thread it can be prefetched in the service worker or dynamically rendered in the service worker.
I demonstrated this concept earlier this year when I published a PWA for the Philly Code Camp. I dive even deeper into using service workers to manage content rendering in my new Progressive Web Application development book.
Why the Chrome Team May Have Created PWA is a SPA Misconception
The Chrome team is great, they provide lots of great content to help developers be more productive and produce better quality web pages. And while their intent is noble it can be misunderstood.
The Chrome team knows there are many sites built using fast food frameworks. They try to be helpful to give developers some guidance on how to make these frameworks work better.
One of those areas is the concept of an 'app shell'.
For single page applications I like to think of the app shell as the primary canvas or context to paint the application, driven by user actions to render updated content.
<HEAD> … <style>…</style> </HEAD> <BODY> <header>…</header> <main>…</main> <footer>…</footer> <script src=“app.min.js”></script> </BODY>
Anyway, the Chrome team has several resources around the concept of the app shell and they do a great job showing how to use this model.
What I hate about this though is many developers and site owners consume this content and assume it is the way to build progressive web applications.
This is wrong.
Using an app shell is a way to drive a progressive web application, but not a requirement.
In fact, I think it may be a bad way to make progressive web apps.
When you use proper service worker caching techniques you should not need an app shell because your pages tend to come from a locally cached response, which when designed correctly should render in a few hundred milliseconds, not 22 seconds!
Why 22 seconds?
That is the average time it takes the average web page to render on an average client device according to Google's research.
The average time it takes to fully load the average mobile landing page is 22 seconds. However, research also indicates 53% of people will leave a mobile page if it takes longer than 3 seconds to load. Mobile Page Speed Benchmarks
Let me be clear, you cannot pre-cache every page of every website. Some sites you can, but not all.
I always use Amazon as my go to example. That's because they have millions of product pages and caching their entire site on a phone or any client computer is just impossible and of course irresponsible.
In these scenarios the use of an app shell is a good idea. But instead of using a single page application you can leverage your service worker to cache page templates and retrieve each page's JSON on demand and render the page in the service worker.
My favorite solution is to leverage a simple template engine, like Mustache, and cached content templates to render pages in the service worker. Or have partial pages pre-rendered on the server and just fetch them. Once the page's content is available you can then push it to the client and make a simple document.querySelector("target-element-selector").innerHTML = [page content HTML].
Without the framework overhead this process feels 'instant' even on average mobile phones.
So a key performance issue is addressed with service workers, but what about links?
Solving Single Page App Linking Issues
The web's primary super power is the ability to deep link. Single page applications tend to use hash fragments, look for the #! in a URL. The hash fragment value triggers a client-side event uses by these frameworks to drive the rendering process. But that hash fragment value is not passed to the server.
In addition to the hash fragment not registering on the server search engines do not index content based on hash fragments.
There has to be a PWA 'best practice' or type of web site, right?
This is where the static website with real URLs wins.
Imagine that, web pages with real addresses solve many problems created by single page applications.
Even if the browser does not support progressive web apps and service workers, which is not many these days, static pages will just work.
My Recommended Progressive Web Application Website Model
If a Progressive Web Application is not a single page application, what is it?
It’s simple, a website that uses the best the web has to offer to deliver great user experiences.
So what is the best the web has to offer? Well that depends on what a site needs.
Some applications need more hardware features, others rich animations or media integrations. But almost all websites have a core common set of expectations.
- Load Fast
- Smooth Animations
- Responsive, Mobile First Design
- Some Dynamic Rendering Capabilities
In the past I was a champion of single page applications, but I can't be anymore. Today I am a progressive web application champion, the natural progression of SPAs.
No surprise there, but this might surprise you:
I now recommend using a static website.
That's right, the original type of website, static and boring.
But unlike when the web originally debuted these static sites are not 100% static, in fact they are not even on a web server.
I use server-side rendering, but I utilize a series of AWS Lambdas that use nodejs to produce static markup when the page's source is created or updated. In other words, the markup is only rendered when the content changes, not on demand and not in the client.
These pages are 'hosted' in AWS S3 and utilize the AWS CloudFront CDN.
I can't tell you how much simpler this configuration is to manage than I used to deal with when using IIS and other web server platforms.
However, there are scenarios when a site might need to be rendered on demand.
For example, when content is driven by an authenticated user's profile. A good example of this is when a site header is personalized for an authenticated user, instead of showing a login button.
It ultimately comes down to how well you can finese these scenarios. If I do need more client-side rendering I am going to limit the scenarios more to what might be called a SPAlet.
This is where a page is responsible for creating an interface to manage or interact with a collection of closely related data. I look at this model as a way to throw back to the original inspiration I had to create early single page apps, a list with a modal dialog to edit records.
Ten years ago I started using jQuery and jQuery UI to design pages. One of the first things I did was modify my forms over data strategy to render data in tables with an edit and new record button.
When a record was selected I would display a modal dialog (in many cases) to enter and update the record data. When the dialog was submitted the data would be posted to the server and the list updated.
Wrapping It Up
Unfortunately many seem to be caught up by the popular misconception that progressive web applications are single page apps. While they can be SPAs they do not have to be SPAs.