Get a Progressive Web App Running in Just 20 Minutes!

Written by: Erik Francis
9 min read

Don't you hate it when you're trying to visit a site on your phone and you get a pop-up that says, "for the best experience, download our app"? You don't want a different app for each website you visit, especially since many are honestly just not very good. Google agrees, which is why they came up with the progressive web app (PWA) concept. At the most basic level, it's just a website. But it has some additional goodies that give it some app-like capabilities on mobile devices. A PWA is fast, secure, available online or offline, and can easily be added to a mobile device's home screen. And any website can be one! In this tutorial, we'll show you how to get one up and running in only 20 minutes while also exploring key tools for understanding and working with PWAs.

What's a PWA?

I've rarely installed apps that should've just been websites. But when I lived in New York City, I liked to read the newspaper on my phone while commuting. The catch was some subway tunnels there don't have internet access. The app would let me read the newspaper on my phone even when offline. But now there's no need for this—PWAs work offline! This magic comes from service workers, which are JavaScript files that your browser runs in the background. True to their name, they're capable of many things. But their coolest feature is that they can utilize the cache to serve a website even when the user is offline. Service workers can also serve push notifications even when the website isn't open. They're key to bridging the gap between apps and websites. A PWA is also like an app in another key way: it's designed to be easily opened from an icon on a mobile device's home screen. To do this, it takes advantage of a manifest, a JSON file that tells the device information about

  • What icons should be used on the home screen.

  • What image should be used as a "splash screen," which shows while loading instead of the browser default, giving a smoother and more app-like experience.

  • A start URL. This is used so that if a user visits your site twice over two separate days within two weeks, your PWA will prompt the user to add it to their home screen. This is a much less annoying option than being greeted with such pleas on your first visit.

  • Your application's "display mode." Different options allow you to hide some parts of the browser's UI such as the address bar, which also makes it feel more like an app.

But beyond that, a PWA needs to be a very fast and secure website that works well on mobile devices. It's served over HTTPS, has a responsive design, loads quickly on 3G, and can handle network instability with grace. This checklist lists the full criteria. Now you might wonder why Google cares. Google has been pushing some of these features for a long time—like speed and HTTPS—and this is another way to encourage their use. Google, for obvious reasons, prefers content live on the website where they can index it, rather than in apps. The PWA concept as it stands right now is just a start towards bringing websites and apps together. Browsers will continue to add more capabilities, such as the ability to control a phone's camera or mic. Unfortunately, not every device supports all the PWA goodies. Newer versions of Android support all of them. Coverage in iOS is spotty unfortunately.

Gatsby: A Fast, Simple PWA Generator

If you look at the checklist, you'll notice any website can meet these expectations. Many developers are updating current popular web development frameworks to make them PWAs or easily configured to be one. My current favorite is Gatsby, a static-site generator powered by React. It's ideal for simple ultra-fast sites. It has some distinct advantages because it was built from the beginning around Google's official PRPL pattern for PWAs. PRPL stands for push, render, pre-cache, and lazy load. And even if JavaScript isn't your thing, it's easy to get it running as a PWA with literally no JavaScript coding of any kind. If you're interested in other PWA options, check out this excellent list. We'll first build our Gatsby site locally and then deploy it to GitHub Pages. To get started, open up a terminal. If you don't already have Node.js available on the command line, I can't recommend nvm (Node.js Version Manager) enough, which allows you to easily install and manage multiple versions of Node.js. I also recommend npm (Node.js Package Manager) for installing packages. You can use npm to install Gatsby as a global command line tool. To do this, run the following command:

npm install --global gatsby-cli

Now head to the directory where you want to create your site and run `gatsby new` and the name of the new directory for your new site. In my case, it's `20-min-pwa`:

gatsby new 20-min-pwa-tutorial

Let's also initialize our git repository. Create a new GitHub repository:

Once you create it, GitHub will show instructions for "push an existing repository from the command line." Head to your Gatsby directory on the command line and follow them to get your site on GitHub:

cd 20-min-pwa-tutorial/
git init
git remote add origin git@github.com:melissamcewen/20-min-pwa-tutorial.git
git add .
git commit -a -m "adding base Gatsby install to our repo"
git push origin master

Gatsby comes with an easy-to-use command line development server. Let's try it so you can see what Gatsby is like. It's easy; just run the following command:

 gatsby develop

Head to localhost:8000 in your browser and take a look!

Auditing PWAs With Lighthouse

Google created a tool called Lighthouse, which is able to automatically audit sites to determine if they are PWAs or not. Simply open up Chrome DevTools and head to the "Audit" tab.

There, you'll be able to select from multiple audits and run them. Select "Progressive Web App." Lighthouse will run its tests and issue a score. Let's try it on our new Gatsby dev site:  

Gatsby out of the box on a development server will only score 21. But there are things Gatsby doesn't build for development that it does build for production.  

So let's run a production build of Gatsby. To do this, shut down your development server by exiting the process and then running the following command:

gatsby build && gatsby serve

The production build is now at http://localhost:9000/. Head there and try running an audit again.

Clicking on each entry provides a short description and a link to the PWA documentation. So we already have some bases covered, though we'll need to retest the server-related ones like page load and HTTPS once we're deployed to a real server on the web. In the meantime, our audit says we lack both service workers and a manifest. Let's set them up.

Creating a PWA Manifest With Gatsby

Gatsby has plugins, which are Node packages that integrate with Gatsby APIs. You install them like any other Node packages, but you also need to add them to your Gatsby config. First, let's install the manifest plugin:

npm install --save gatsby-plugin-manifest

A base config is available in the documentation. Open up the gatsby-config.js file in your Gatsby directory and paste it in. It should look like this:

module.exports = {
  siteMetadata: {
    title: 'Gatsby Default Starter',
  },
  plugins: [
  'gatsby-plugin-react-helmet',
  {
    resolve: `gatsby-plugin-manifest`,
    options: {
      name: 'GatsbyJS',
      short_name: 'GatsbyJS',
      start_url: '/',
      background_color: '#6b37bf',
      theme_color: '#6b37bf',
      display: 'minimal-ui',
      icon: 'src/images/icon.png', // This path is relative to the root of the site.
    }
  }
  ],
}

  I chose this beautiful image and saved it as src/images/icon.png. I also customized my colors to make the theme color a nice purple. You can see the options for display and other values in the MDN documentation.  

It's that easy! I used to have to manually make all the different images or use a third party tool, but now Gatsby does it automatically though you can override them if you want different images for different OSs. Now let's confirm our manifest works. Restart your server in your terminal. Open up the "Application" tab in the DevTools, then click "Manifest." If you configured your manifest correctly, you'll see the values here and your icons displayed:

Set up a Service Worker to Let Your Site Work Offline

Gatsby also has an easy-to-use plugin called gatsby-plugsin-offline that gets a service worker set up to serve your site offline:

npm install --save gatsby-plugin-offline

Now let's add it to our config. Make sure you add the service worker to your config file AFTER the manifest. It should look like this:

module.exports = {
  siteMetadata: {
    title: 'Gatsby Default Starter',
  },
  plugins: [
  'gatsby-plugin-react-helmet',
  {
    resolve: `gatsby-plugin-manifest`,
    options: {
      name: 'GatsbyJS',
      short_name: 'GatsbyJS',
      start_url: '/',
      background_color: '#6b37bf',
      theme_color: '#6b37bf',
      display: 'minimal-ui',
      icon: 'src/images/icon.png', // This path is relative to the root of the site.
    },

  },
  'gatsby-plugin-offline'
  ],
}

  Restart your build and let's head back to your "Application" tab in DevTools. Click "service workers" and you should see your new service worker with some info about it:

Now if anything goes wrong for you in this process, head to "Clear storage" where you can clear out the cached values and "unregister" service workers.

Deploy and Audit Your PWA

Now we're ready to deploy. First, we need to do special configuration because unless you have a custom domain, GitHub Pages serves repository sites from a subdirectory. If you're not doing this, you can skip this part. Add the path prefix value to our config and change the values in the manifest for start_url :

module.exports = {
  siteMetadata: {
    title: 'Gatsby Default Starter',
  },
  plugins: [
  'gatsby-plugin-react-helmet',
  {
    resolve: `gatsby-plugin-manifest`,
    options: {
      name: 'GatsbyJS',
      short_name: 'GatsbyJS',
      start_url: '/20-min-pwa-tutorial',
      background_color: '#6b37bf',
      theme_color: '#6b37bf',
      display: 'minimal-ui',
      icon: 'src/images/icon.png', // This path is relative to the root of the site.
    },

  },
  'gatsby-plugin-offline'
  ],
}

  The Node GitHub Pages package makes publishing it to GitHub Pages very easy:

npm install gh-pages --save-dev

Head over to your package.json file in your Gatsby root directory and add "gatsby build --prefix-paths && gh-pages -d public" to "Scripts" as "Deploy" so you can easily run it from the command line:

{
  "name": "gatsby-starter-default",
  "description": "Gatsby default starter",
  "version": "1.0.0",
  "author": "Kyle Mathews <mathews.kyle@gmail.com>",
  "dependencies": {
    "gatsby": "^1.9.238",
    "gatsby-link": "^1.6.39",
    "gatsby-plugin-manifest": "^1.0.15",
    "gatsby-plugin-offline": "^1.0.15",
    "gatsby-plugin-react-helmet": "^2.0.8",
    "react-helmet": "^5.2.0"
  },
  "keywords": [
    "gatsby"
  ],
  "license": "MIT",
  "scripts": {
    "deploy": "gatsby build --prefix-paths &amp;&amp; gh-pages -d public",
    "build": "gatsby build",
    "develop": "gatsby develop",
    "format": "prettier --write 'src/**/*.js'",
    "test": "echo \"Error: no test specified\" &amp;&amp; exit 1"
  },
  "devDependencies": {
    "prettier": "^1.11.1"
  }
}

Now running it is as easy as

npm run deploy

If you're unsure of the URL, head to the repo settings in GitHub and it should be there.  

Now it's time to do our final Lighthouse audit. You should be at 100% now!

Next Steps

Lighthouse helps us with most of the auditing, but there are still a few items that need to be manually verified. These are at the bottom of the list, and you can click on each item for more info.  

Our final PWA doesn't do much, but this is a great base for a website. And no matter what framework you decide to build your own PWA in, the tools for evaluating PWAs are the same. Next time you're considering building an app, you might try building a PWA instead. Or if websites are already your thing, you should think about whether a PWA would give your users a better experience.

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.