Register for this year’s #ChromeDevSummit happening on Nov. 11-12 in San Francisco to learn about the latest features and tools coming to the Web. Request an invite on the Chrome Dev Summit 2019 website

1. Get set up

Navigate into the offline-quickstart-lab/app/ directory and start a local development server:

cd offline-quickstart-lab/app
npm install
node server.js

You can terminate the server at any time with Ctrl-c.

Open your browser and navigate to localhost:8081/. You should see that the site is a simple and static web page.

Note:Unregister any service workers and clear all service worker caches for localhost so that they do not interfere with the lab. In Chrome DevTools, you can achieve this by clicking Clear site data from the Clear storage section of the Application tab.

Open the offline-quickstart-lab/app/ folder in your preferred text editor. The app/ folder is where you will be building the lab.

This folder contains:

images/ folder contains sample images

styles/main.css is the main stylesheet

index.html is the main HTML page for our sample site

package-lock.json and package.json track app dependencies (the only dependencies in this case are for the local development server)

server.js is a local development server for testing

service-worker.js is the service worker file (currently empty)

2. Auditing the site with Lighthouse

Before we start making changes to the site, let's audit with Lighthouse to see what can be improved.

Return to the app (in Chrome) and open the Audits tab of the Developer Tools. You should see the Lighthouse icon and configuration options. Select "Mobile" for Device, select all Audits, select either of the Throttling options, and choose to Clear storage:

Click Run audits. The audits take a few moments to complete.

Explanation

You should see a report with scores in Developer Tools once the audit is complete. It should show scores, something like this (the scores might not be exactly the same):

Note: Lighthouse scores are an approximation and can be influenced by your environment (for example, if you have a large amount of browser windows open). Your scores might not be exactly the same as those shown here.

Now return to the browser and refresh the site. Check the console to see that the service worker:

registered

installed

activated

Note: If you already registered the service worker previously, or are having trouble getting all the events to fire, unregister any service workers and refresh the page. If that fails, close all instances of the app and reopen it.

Next, terminate the local development server in your command line by running Ctrl + c. Refresh the site again and observe that it loads even though the server is offline!

Note: You may see a console error indicating that the service worker could not be fetched: An unknown error occurred when fetching the script. service-worker.js Failed to load resource: net::ERR_CONNECTION_REFUSED. This error is shown because the browser couldn't fetch the service worker script (because the site is offline), but that's expected because we can't use the service worker to cache itself. Otherwise the user's browser would be stuck with the same service worker forever!

Explanation

Once the service worker is registered by the registration script in index.html, the service worker install event occurs. During this event, the install event listener opens a named cache, and caches the files specified with the cache.addAll method. This is called "precaching" because it happens during the install event, which is typically the first time a user visits your site.

After a service worker is installed, and if another service worker is not currently controlling the page, the new service worker is "activated" (the activate event listener is triggered in the service worker) and it begins controlling the page.

When resources are requested by a page that an activated service worker controls, the requests pass through the service worker, like a network proxy. A fetch event is triggered for each request. In our service worker, the fetch event listener searches the caches and responds with the cached resource if it's available. If the resource isn't cached, the resource is requested normally.

Caching resources allows the app to work offline by avoiding network requests. Now our app can respond with a 200 status code when offline!

Note: The activate event isn't used for anything besides logging in this example. The event was included to help debug service worker lifecycle issues.

Optional: You can also see the cached resources in the Application tab of Developer Tools by expanding the Cache Storage section:

4. Re-audit the improved site

Restart the development server with node server.js and refresh the site. Then open the Audits tab in Developer Tools again, and re-run the Lighthouse audit by selecting New Audit (the plus sign in the upper left corner). When the audit is finished, you should see that our PWA score is significantly better, but could still be improved We'll continue to improve our score in the following section.

5. Optional: Add to Home Screen

Our PWA score still isn't great. Some of the remaining failures listed in the report are that the user will not be prompted to install our web app, and that we haven't configured a splash screen or brand colors in the address bar. We can fix these issues and progressively implement Add to Home Screen by satisfying some additional criteria. Most importantly, we need to create a manifest file.

5.1 Create a Manifest file

Create a file in app/ called manifest.json, and add the following code:

Return to the site. In the Application tab of Developer Tools, select the Clear storage section, and click Clear site data. Then refresh the page. Now select the Manifest section. You should see the icons and configuration options that are configured in the manifest.json file. If you don't see your changes, open the site in an incognito window and check again.

Explanation

The manifest.json file tells the browser how to style and format some of the progressive aspects your app, such as the browser chrome, home screen icon, and splash screen. It can also be used to configure your web app to open in standalone mode, like a native app does (in other words, outside of the browser).

Support is still under development for some browsers as of the time of this writing, and the <meta> tags configure a subset of these features for certain browsers that don't yet have full support.

We had to Clear site data to remove our old cached version of index.html (since that version didn't have the manifest link). Try running another Lighthouse audit and see how much the PWA score improved!

5.2 Activating the install prompt

The next step to installing our app is to show users with the install prompt. Chrome 67 prompted users automatically, but starting in Chrome 68, the install prompt should be activated programmatically in response to a user gesture.

Add an "Install app" button and banner to the top of index.html (just after the <main> tag) with the following code:

Save the file. Open the app in Chrome on an Android device, using remote debugging. When the page loads, you should see the "Install app" button (you won't see it on a desktop, so be sure you are testing on mobile). Click the button and the Add to Home Screen prompt should pop up. Follow the steps to install the app on your device. After installation, you should be able to open the web app in standalone mode (outside of the browser) by tapping the newly created home screen icon.

Explanation

The HTML & CSS code adds a hidden banner and button that we can use to allow users to activate the installation prompt.

Once the beforeinstallprompt event fires, we prevent the default experience (in which Chrome 67 and earlier automatically prompts users to install) and capture the beforeinstallevent in the global deferredPrompt variable. The "Install app" button is then configured to show the prompt with the beforeinstallevent's prompt() method. Once the user makes a choice (to install or not) the userChoice promise resolves with the user's choice (outcome). Finally, we display the install button once everything is ready.

Congratulations!

You've learned how to audit sites with Lighthouse, and how to implement the basics of offline functionality. If you completed the optional sections, you also learned how to install web apps to the home screen!

More resources

Lighthouse is open source! You can fork it, add your own tests, and file bugs. Lighthouse is also available as a command line tool for integration with build processes.