From understanding to creating Progressive Web Apps
Imposter syndrome
Back in 1978, the imposter phenomenon was introduced and defined as an individual experience of self-perceived intellectual phoniness (or simply: fraud).
A common feeling associated with the imposter syndrome is anxiety about being fake. Simply put, "imposters" assume that they give the false impression of being more competent than they actually are. They exhibit deep feelings of inadequacy and self-doubt when it comes to their knowledge and expertise.
Have you ever felt like it’s only a matter of time until you’re exposed as a fraud?
If your answer is affirmative, you don’t have to worry about it. Welcome to the club.
Our club is pretty large, including big players such as Michael Uslan, Denzel Washington, Chris Martin and the list can go on. Oh, Maya Angelou and Albert Einstein were a part of it too.
At this point you might be asking: “Hold on dude, what does this have to do with Progressive Web Apps?”.
Keep reading.
A while ago I used to think that a Progressive Web App (or PWA) was a Web System that would behave just like a native app when accessed from a mobile phone.
I was feeling that my definition was incomplete and that I was missing something, but I had a hard time admitting that I don't fully get what a PWA is.
The “good news” came after reading more articles on this topic, because I found that a lot of developers believe that everyone else besides them understands PWAs. And they’re afraid being exposed.
That’s the imposter syndrome!
A common practice that can help you overcome it is to reframe failure as a learning opportunity.
You came to the right place; in the following lines we'll clarify what a PWA is and we'll create one from scratch, using React.
How to define PWA
We can all agree that a major part of the mobile web is failing to be fast and responsive. For people in environments where the internet connection is slow or the internet packages are lost sometimes, the mobile web is failing even harder. Let’s see if using the PWAs approach is going to fix that.
The official documentation states that PWAs are more reliable, fast and engaging.
What does that mean for the end users?
Reliability: PWA responds with meaningful content, despite the network conditions. All the credits to service workers. A service worker is a script that runs in a separate thread from the main browser one, intercepts network requests, enables rich caching, push notifications or background sync. Using service workers:
- When offline, the PWA is capable to render relevant content due to intelligent caching.
- The background content is updated, also known as the “fresh” attribute.
Fast: PWA responds quickly and smoothly to user’s interactions, just like a native app does. How? PWAs pre-load and store your website content on the user’s device while they browse. In more detail, when a user visits the website for the first time, the service worker is installed and the Application Shell is cached. The App Shell architecture is the code required for an application to render relevant content and to be functional in a fast and performant way, which includes the offline mode as well. The App Shell consists of the entire JS, HTML, CSS package, fonts and images that powers the UI. Service workers store locally the UI into the browser cache of the device storage. On the following visits, the first render is accelerated by serving the cached shell from the service worker.
Engaging: because a PWA is:
- Easy to install. No App Store or Google Play needed.
- Easy to discover: directly from the home screen. Thanks to service workers and manifest file. The manifest is a JSON file that offers the ability to customize “native” features like how the app appears and how it’s launched.
- Linkable, so it’s easy to share because any screen can have a different link.
- Responsive. Thanks to manifest file, they offer an immersive full-screen.
- Re-engaging, due to send notifications capability, so again, thank you service workers!
The above attributes of a PWA definitely translates into solutions for the shortcomings of the mobile web.
Let’s wrap up the above lines into a short-ish paragraph:
PWAs are Web Systems that are capable to give users a mobile native-like experience and more. They are fast, they can work offline and they can be easily added to phone’s home screen. They also add the best from the web, as they are linkable and secured.
A Web System can be considered a PWA if it meets the following main criteria:
1. Switches to a secure network. (HTTP -> HTTPS).
2. Has a valid manifest file which consists metadata.
3. Includes a service worker.
Now that we have clarified what a PWA is and we understand the requirements for an app to become a PWA, let's go create one ourselves.
How to create a PWA
We're going to create a PWA from scratch and we're going to call it "News4All". This will be a very simple Web System that will make requests to newsapi.org in order to render news.
The app will consist of two main modules: listing one, where news will be listed, and details, where the full news item will be shown.
We’re going to build it using Node.js, ReactJS, redux, redux-thunk and redux-persist.
The purpose of this section is to share the key points that must be followed in order the create a PWA using create-react-app. This is why I’m not going to share the entire App Shell architecture in this article.
We’re going to initialize the web app using create-react-app. This is a modern CLI that can be used to initialize a React app in a very fast way, because you don’t have to worry about the entire build setup that includes Webpack configs and running scripts.
As the official doc states, the generated environment by create-react-app is everything you need to build a modern application that uses: React, JSX, ES6, Autoprefixed CSS, and more. The environment also meets the PWA criteria. They offer a service worker together with a manifest file out of the shelf.
Make sure you have the latest version of create-react-app. If you don’t have it, install it globally by running:
>> npm install -g create-react-app
Initialize your application:
>> create-react-app news4all
Now if we look at the result we’ll find the needed files, manifest.json (under ~/public) and serviceWorker.js (under ~/src).
create-react-app disables the service worker by default, so in order to change this we must go to ~/src/index.js
and register it:
In order to customize how your app will display on the home screen or how it will launch, we have to specify inside manifest file fields like app name, app icon or splash screen. As stated above, the purpose of the manifest is to deliver a native-like UX.
{
// The name that appears on the home screen. Can be customized by the user only on iOS.
"short_name": "News4All",
// The name that appears on the splash screen if no custom splash has been added.
"name": "News4All",
// The app icon and splash screen one.
"icons": [
{
"src": "icon192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icon512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
// The url that will load when the app is launched.
"start_url": ".",
// Display mode (standalone: allows the app to run inside a different window, to have own app icon and splash screen, et. c.)
"display": "standalone",
// The color that surrounds the app (topbar for instance)
"theme_color": "#000000",
// The background color of the website (can show up when the website is loading for instance)
"background_color": "#ffffff"
}
When it comes to the splash screen and app icon for Android, Chrome automatically shows the splash screen as long as we meet the following requirements in the above web app manifest:
- The name property is set to the name of your PWA.
- The background_color property is set to a valid CSS color value.
- The icons array specifies an icon that is at least 512px by 512px.
- The icon exists and is a PNG.
As for iOS, this doesn’t do the trick as we need to follow some extra steps.
Although documented on Apple’s Safari Web Content Guide, setting them up might be a challenge for a lot of developers.
First, in order to make the app behave like a native one - without Safari or URLs shown at the top of the screen - we have to set the apple-mobile-web-app-capable
meta tag to yes so as to turn ON standalone mode.
In the head of our your ~/public/index.html, we add:
<meta name="apple-mobile-web-app-capable" content="yes">
In order to add a splash screen we have to add the following line in the same file:
<link rel="apple-touch-startup-image" href="/launch.png">
What the official documentation fails to mention is that the href
attribute has to point to an image with a resolution that matches the one from the iOS device running the app. The solution for this is to use the media
attribute.
<link href="assets/ios/iphone5_splash.png" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="assets/ios/iphone6_splash.png" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="assets/ios/iphoneplus_splash.png" media="(device-width: 621px) and (device-height: 1104px) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image" />
<link href="assets/ios/iphonex_splash.png" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image" />
<link href="assets/ios/iphonexr_splash.png" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="assets/ios/iphonexsmax_splash.png" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image" /> <link href="assets/ios/ipad_splash.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="assets/ios/ipadpro1_splash.png" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="assets/ios/ipadpro3_splash.png" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="assets/ios/ipadpro2_splash.png" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
Moving on to the app icon, in order to customise it for different resolutions, we have to place the icons inside the ~/public folder, as well as specify them inside the index:
<link rel="apple-touch-icon" href="icon152x152.png" />
<link rel="apple-touch-icon" sizes="152x152" href="icon152x152.png" />
<link rel="apple-touch-icon" sizes="167x167" href="icon167x167.png" />
<link rel="apple-touch-icon" sizes="180x180" href="icon180x180.png" />
By now we should have a service worker and a manifest set up.
To have it work under HTTPS, we need to deploy the application to an environment that serves it through HTTPS as this is a requirement for a legit PWA.
For demo purposes, we’ll accomplish this by using now sh, as is offers the possibility to easily deploy apps and
serve them via HTTPS for free. What we have to do is install the now
CLI (by running npm i -g now
) and create an
account. You could use a different approach to deploy to your own CDN using AWS S3 and CloudFront. You can find more
information about this on our blog at How to Best Engineer you Website and How to Best Engineer your Website 2.
now
gives us different solutions to deploy a react application, like:
- Using a Node.js/Express server from where the static assets will be served.
- create-react-app: here we have to ask
now
to make the build of our application. - Static deployment: we have to generate the build locally and now will take care of it.
We’ll go with the static deployment solution. Being placed at the root of our project, we have to run:
>> npm run build
This command will create a minified bundle. The service worker will be registered as well.
At this point we want to go the the generated /build folder and ask now
to take care of all the assets from this directory.
>> cd /build
>> now
You will be prompted about the account created earlier.
After that, they deliver you a now
URL, similar to this one: https
Now that we have our application deployed, let’s verify if our app fulfills the criteria for being a PWA. How do we do this? We’re going to use Chrome (60 and up) Audits Panel from the developer’s console, since it includes tests for PWA, performance, accessibility, and best practices. This panel is powered by Lighthouse, a free and open-source automated tool for improving the quality of the web.
All you have to do is fire up Chrome, go into your developer console, select Audits
panel and click on the magic button.
At this point we can say that our app is a proper PWA, as it meets the following criteria:
1. It redirects from HTTP to HTTPS.
2. It uses a service worker.
3. It has a valid manifest file.
Demo
Our project is hosted on Github; for the purpose of this article, I only shared a part of the code. That being said, I will share the final result of the News4All Progressive Web App.
Desktop
Android
iOS
1. From the browser (Safari on iOS/Chrome on Android) we navigate to https://build-5137uyqmy.now.sh/.
2. We add it to the HomeScreen, for iOS we choose a custom name if we want to, and that’s it. We find that News4All is hosted on the HomeScreen, no AppStore or GooglePlay involved.
3. When News4All is opened, it does in fact behavelike an app: custom icon, splash screen, immersive full-screen.
4. We exit our app and go offline now.
5. Open the app again and the previous content is there, due to the App Shell created. Now you can navigate through the app even offline.
Github Link: https://github.com/MCROEngineering/news4all-pwa-demo
Conclusion
It's perfectly understandable if you didn't quite get PWAs at first. There are a lot of developers out there in the exact same situation. Part of the struggle might be related to the term itself, which, as it turns out, is more of a marketing thing. But this is a story for another time.
Our mission and responsibility as developers is to make the world a better place, even when it comes to the mobile web. For this reason we should focus more on the benefits that Progressive Web Apps bring to the table.