Creating fast and engaging mobile web experiences has been one of my biggest challenges since starting my research on Progressive Web Apps one year ago. In this post, I’ll cover some of my experiences during the creation of my latest PWA.
With the knowledge I’ve gathered over the year I wanted to make a better version of Offline Gallery, one of my first PWAs. While thinking about how to improve it I remembered a quote from the Preact website.
After reading it I asked myself the question: Is it possible to make Preact the bigger part of my bundle while still delivering a feature-rich experience? In technical terms, this would result in a JS bundle that’s only 6kb in size.
And so that’s what I did.
Bundle size and tracking
To keep track of the bundle size and keep it as small as possible there are a few things to consider. During development, I used Preact CLI (which under the hood uses Webpack) to compile and serve my bundles. After every big structure change or added feature, I ran a production build (with gzip size).
To make the end result even smaller I switched to Rollup for my production build. This reduced the size of my bundle by another 10%! Keep in mind that this number is based on an already very small bundle so you might not experience the same size reduction with bigger applications.
Starting off with the challenge in mind the most important thing was choosing a setup. As the name suggests the only installed dependency, for the front-end at least, was Preact: a fast 3kB alternative to React with the same modern API.
For the back-end of the application, I use Node with Polka, a micro web server, to quickly send the full output to the client. An important note here is that CSS and JS are inlined for production so it’s only a single request. The expected response is stored as a Buffer with Unvault so it’s available quickly.
The core feature of Preact Gallery is the ability for users to add, edit and remove images. Out of context, it feels like an easy job but with modern functionality like the Service Worker, it becomes way more interesting.
Adding an image to the gallery involves a few different steps:
- The user provides an image URL which is then passed to the Service Worker using postMessage. By providing a type and value we can specifically tell the Service Worker what to do: insert or remove.
- The URL is then parsed to a base64 string and fetched from the server. On the server, the received data is sanitized and validated. Once that is done the image is loaded and send back to the client together with the content length header to give the user insight into data and storage usage.
- When the image is cached by the Service Worker and is visible to the user the source is placed in localStorage so we can keep track of added images and show them offline.
The functionality of this process is progressively enhanced as it also works without Service Worker. This simplifies the steps to just inserting the image in the DOM and adding it to localStorage. Nothing fancy here.
The Service Worker allows us, developers, to give the user full control over their cache: Add an image for offline viewing and delete it when it’s no longer needed to save precious storage space.
One feature I think every application should have is a night mode. Adding it to Preact Gallery wasn’t hard: toggle a single class on the body and let CSS take care of the rest with the current state being stored for repeat visits.
To keep it scalable as the application might require more settings later, I decided to reuse the form modal to also work as a list of toggles. Switching the content of the modal instead of creating a new component was beneficial in a way that the GPU layer, used for the transition, only exists once and the controls for opening and closing it is consistent.
The second option was based on total storage used by images and the ability to remove them all at once. Pressing this option will send an event to the Service Worker with type removeAll to clear everything in the image cache.
Progressive Web App
As with all of my web experiments, this one should be no exception and qualify as a Progressive Web App. What this primarily means is that the core experience should work on all browsers while providing an enhanced version for modern browsers that support new features like Service Worker.
These enhancements are visible in a few ways:
- It’s tested and works on all major browsers (including IE).
- If Service Worker is available the application works offline.
- If postMessage is available the user has control over their storage.
- Web Application Manifest is added so it can be added to the home screen.
Something more experimental I’ve tested during development is the ability to swap the favicon, web application manifest (with icons) and theme color when switching to night mode. This allows for a more integrated experience and provides the user with a different home screen icon (defined on add).
The addition of a dynamic web application manifest or customisable icons from within the app could improve the user experience by making it feel more at home.
Besides setting up the domain and SSL (with the help of a great colleague) and testing if everything worked properly there’s one thing left to do: run Lighthouse!
Lighthouse is an open-source, automated tool for improving the quality of web pages. It will provide you with a score of 0 to 100 for 5 different audits based on multiple tests in that category. After a quick run, you’ll see a list of improvements or features you have implemented correctly which is helpful!
The ability to create a working application that comes in at just 8kb in size is really incredible to me. For many projects, I wouldn’t expect a result like this but with Preact you’re already off to a good start.
It’s good for the quality of your application to keep track of your bundle size. Compare included functionality against size increase to see if it’s worth the cost.
The source for this project can also be found on GitHub.
Feedback and thoughts are much appreciated, thanks! 🙇