 Hi, I'm Sarah Clark, and I'm here to show you how to convert an ordinary website into a progressive web app. When we look at Google's PWA checklist, two requirements stand out. All app URLs load while offline and metadata provided for add to home screen. You may remember that we can use a service worker to cache assets to work offline. Sam also mentioned you can add icons to the home screen using a manifest file or special meta tags. Let's take an ordinary website and turn it into a PWA. First, we'll run Lighthouse. We already know what to expect, but this is a good habit to get into. We need an HTTP or an HTTPS URL to run Lighthouse. A file URL won't do. We'll use the web server for Chrome extension, though you can use any web server you like. Now we can run Lighthouse, and as expected, it says we need a service worker and we don't work offline. Let's solve the first problem, adding a service worker. Begin by creating an empty sw.js file at the same level as your home page. You might be tempted to create this in a sub folder, but for now it has to be at the top level. Now we'll add the code to load the service worker. Open index.html and add a script block. Add a check to see if the browser has implemented service workers. You could check for window.navigator.serviceworker or use the service worker in navigator test we show here. This is an example of progressive enhancement. The site will keep working on any browser that doesn't implement service worker. It just won't get the offline feature. But if service worker is available, we will enhance the site to work offline. We can add a single line to register the service worker. We're cheating a little bit by not adding any error reporting. We'll show you the right way to do this once you have learned a little bit more about JavaScript promises. But for now, let's press on. Open sw.js. This code will run inside the service worker and control the cache. First, add a list of all the files in your site. These will go into the cache. Also define a name for the cache and include a version number. Notice that you want both slash and index.html, as those are both names for the same thing. Also note that I'm using const here to define constants. This is part of ES2015 and is optional. Feel free to use var instead if you like that better. Now we can load the files into the cache. The service worker will receive an install event during registration. This is our cue to put the files into the cache. We'll add a listener for it. Notice the self keyword. In a worker, self is the worker. Everywhere else, self is the window. In other words, self is the current global object. If you're not sure what that equals greater than fat arrow means, it's another way to define a function. This was introduced in ES2015. You can also write it as an anonymous function with a single event parameter. This code adds all the files to the cache. Let's take it from the inside out. The innermost call is cache.atall. This takes a list of resources, loads them from the network, and puts them in the cache. Moving out of level, we have to create and open the cache before we can add files. Now if you've ever written a network or file IO code, you know that the browser runs these asynchronously. This means that the browser runs the operation in the background and notifies you when it's finished. Many asynchronous operations use a callback or an event to signal completion. The service worker uses a newer technique called promises. Caches.open returns a promise, a special JavaScript object that performs work in the background. When you call then on a promise, you give it a function to execute after the promise is done. This function will receive the result of the prior function. In this case, we receive the cache from the open function and add all of the files to it. Adding all of the files also happens in the background. We could add another then clause at the end to run after the add all if we wanted to. In this case, we don't need to, but we have a problem. All of this asynchronous work is happening inside an event handler. When you call caches.open, it starts working in the background and returns immediately. Unless we do something to prevent it, this means the install event handler would return before the cache is ready, and that would be bad. We can fix this by wrapping the code in event.waituntil. This will wait for the last promise in the series to complete before returning control to the event handler. Now if you were in Lighthouse again, you should see that the app has a service worker. And if you open the Chrome Developer Tools, you can look at the contents of the cache. All of your files are in there. Lighthouse reported that our app has a service worker, but it doesn't work offline. Let's fix that. We have the files in the cache, and now we want to get them out. Remember that the service worker sits between our site and the network. The service worker can intercept requests to the network and divert them into the cache. When this happens, the service worker receives a fetch event. So we need to add a fetch event handler to the service worker. How should we respond to this event? We need to find the file we cached earlier and return it. caches.match takes the fetch request and returns the matching result from the cache. What happens if the file isn't in the cache? caches.match will return null, and that's not good. What we really want is to try the cache first, and if the file is missing, go ahead and try the network. This is called the cache-first strategy. We need to make a change to our code. If the match returns null, go ahead and fetch the request from the network. If you're looking for the if statement, we're using a bit of idiomatic JavaScript here. The two vertical bars are the logical or operator. It evaluates and returns the left-hand side unless it's null or false. Otherwise, this operator evaluates and returns the right-hand side. So in plain English, if the cache response is not null, return it. If it is null, return the result of calling fetch. Event.respondWith waits for the innermost promise to resolve and then returns its value. This will either be a match or the result of calling fetch. Now we come back and run Lighthouse again. If all goes well, offline support works now. If something went wrong, here are some debugging tips. First, are you running a web server? If you're on local host, HTTP is fine. But if you're not on local host, the service worker requires HTTPS. Second, check the browser console. If the service worker is failing to load the script, it could be a syntax error. Also, check that your script is in the right place. It has to be at the top level of your site with index.html. Now you should have a website that works as a PWA. If that went by a little quickly, check out the Codelabs link. It has all the steps and a starter website. If you're ready for more, the next episode has all the details on adding your PWA to the home screen. Until then, have fun building your first PWA.