In the beginning, there was HTML and it was good. Websites were light weight, albeit a tad boring. Innovation on the world wide web was as slow as our dial-up connections as we wasted seconds our lives waiting for that adorable animated gif of a cat chasing its own tail to load.
So, how do we maintain the interactivity of today while still reaping the performance rewards of those simpler HTML, CSS, and JS sites of decades ago? Simple: time travel. In other words, make static content static again through caching and pre-rendering.
What is a Progressive Web App?
An emerging trend in web development is the big brother of responsive design; Progressive Web Apps (PWA). Where responsive design focused on making apps visually scale down to be viewed on mobile devices, PWAs are attempting to merge the best features of mobile apps and websites. Service workers are allowing for offline usage, content caching, live content updating, and push notifications all while not requiring the download and installation process of a mobile application. Combine this technology with server side pre-rendering of content and code and you end up with a powerful toolkit for improving the user experience.
Three Common Cases
Although there are many very cool features with Progressive Web Apps (PWA), in this post we will be focusing on how caching and pre-rendering your application can vastly improve the perceived performance for visitors. Obviously, before we proceed, it should go without saying that decoupling your front end code from any backend code should be your first priority. Distilling all interactions with the backend down into API calls allows for far more flexibility regarding front end delivery options.
Here are three common scenarios that most websites fall into and the technique that can be applied to improve a visitor’s overall perception of performance.
1. Caching and Pre-rendering Static Content
If sections of your website do not change, popular front end frameworks like React and Angular (Angular Universal) can pre-render your page on the server. This affects the user experience in two ways:
- You can host the prerendered code on a CDN making for quick downloads and high availability.
- Because the application does not need to bootstrap or render the DOM before displaying the page, the time to first paint (the moment something appears on the screen) is shorter, giving the user a perceived sense of performance.
In situations, such as blogs, where the content isn’t static but the updates are infrequent, coupling this prerendered content with a service worker that caches the current version then checks for new, updated content, is an ideal solution.
2. Handling limited interactivity
If a majority of your application is static but there are a few elements that are interactive, such as recipes with a discussion area or products in a store where only the price and availability frequently change, then it is time to split up responsibilities. Much like in our first example, your static content can be loaded quickly using a combination of server-side rendering, CDN, and local caching. However, in this instance, you have two options for the dynamic areas of your web page:
- Load them separately. In the static copy of the site, fill those dynamic areas with loading animations. Use a service worker to replace those areas of the page when the actual page loads/renders in the background.
- The second option is a little more difficult but can make for an impressive user experience. Render static/cached versions of your interactive areas. The danger of this is your user interacting with these areas before they are fully loaded. To combat this, employ a script such as replay.js. This will allow you to capture any actions that a visitor may have taken and then replay them onto the newly loaded page. If implemented thoughtfully, it allows for a fast, seamless experience, so while a little more difficult, this can make for an impressive user experience.
3. App Shell
Finally, for highly interactive webpages, there is App Shell. The concept of an App Shell is to only take the very outside of the app, things like navigation and general outer layout, and cache/pre-render it. Since menus, logos, headers, footers, and overall look and feel are far less likely to change over time, this gives your visitors reassurance that they have connected to your website, even while the service worker takes the time to load, bootstrap, and render the actual dynamic content. This would be ideal for sites dealing with frequent updates like news and social media.
- Use a modern JS library to pre-render the static elements of your application to limit the time to first paint, this will be perceived as better performance by your visitors and give you more delivery options.
- Leverage service workers to locally cache infrequently updated content then to reach out to APIs for updates if/when available.
- Consider libraries like replay.js which record user interactions allowing interactive elements to be pre-rendered while not losing any actions that occurred before the actual bootstrapping of the app.
But Wait There’s More:
Stay tuned for these blogs and more from ng-conf 2017 by the ExcellaJS team:
- Taking Control with Angular CLI: Brendan Sawyer
- Ng-conf 2017 Talks You Should Watch: Alex Hoffman
- Serverless Development with Angular, Firebase and Cloud Functions: Sam Blissard
- Three Common Questions for TypeScript Beginners: Cameron Ivey
- Three Common Cases for Universal Rendering in Progressive Web Apps: Keith Center