Check out a free preview of the full Progressive Web Applications and Offline course:
The "Challenge 10: Solution" Lesson is part of the full, Progressive Web Applications and Offline course featured in this preview video. Here's what you'd learn in this lesson:

Mike walks through the solution to Challenge 10.

Get Unlimited Access Now

Transcript from the "Challenge 10: Solution" Lesson

[00:00:00]
>> Mike: The first thing we'll gonna do is add a little enhancement on top of the last solution. So that we kinda put a bow on it, and we get rid of the situation where we had kind of fallback images for everything in the event that we turned out API off.

[00:00:17] And the solution here is, I'm sure there's a smarter way to do it, but in the moment I'm just reaching for something that is obvious, and easy to understand and read. And it's just going to involve duplicating a little code. Now, let's look at the way that we were handling JSON data here.

[00:00:39]
>> Mike: So we've got fetchApiDataWithFallback. And in many of the situations where we're first fetching something and if it comes back and things didn't work out, we then reach into the cash. Oftentimes if we get the response, that's great, we just use it. In this case we are doing some stuff beforehand.

[00:00:59] I'm just going to copy this and go up to where we are handling our image stuff. And here we've got the request for our image, here's the situation where we get a 404, here's the situation where things look good, where we're getting the real image. I'm just going to paste this here, and the only thing I have to do now is open the cache up so that we get that cache, right?

[00:01:25] Remember, we had cache.open around this whole function here. So I'm just going to copy that line actually. Beep boop. And we will do something like this, return that, it already has return. Return this thing, it's a promise, right? Inside the promise we can paste this stuff.
>> Mike: And at this point, it should work.

[00:01:57] So, I'm gonna start the server back up. I'm gonna increment my cache, actually it shouldn't even matter now. This kind of cache here, it's just sort of as things go through it, we're storing it for later, right? We don't need the installation or activation process. That might require us to sort of bump a version here.

[00:02:18] So I fired it up. And it's building the app, and here we go. Okay, so here's the fallback image that we expect, this little question mark up top, and now we've seen all these images. I just want to go and look in my Application tab here into the cache's section.

[00:02:40] Refresh it, and great. So now in my Fallback section, not only do I have a lot of JSON here, these things that begin with API, but I've got a ton of images below that. So now, this is all the same category of data. It's stuff that we would prefer to use the fresh version, if we lose a connection, we're gonna use the stuff that we have kept for later.

[00:03:08] So now, kill the server, start our npm run watch. Let it do its thing, and when I refresh,
>> Mike: Damn it.
>> Mike: All right, we're not gonna go down that rabbit hole. You had it working though, so it is possible. I'm probably just missing something obvious. That being said, the fallback image makes this not a breaking issue here.

[00:03:43] Let me just,
>> Mike: I'm just gonna save this for later.
>> Mike: All right, so now we're kind of back to the starting point here. So now we're gonna go through the solution for the index.html portion of this exercise. And the first thing I wanna do is I wanna make sure that as part of the installation process of the service worker, by the time it is activated, we must have an index.html cached.

[00:04:19] That's one file that we are going to use no matter what path a user enters our app through. So they might be on the /orders page where they can see all of the orders that we have placed. We're still gonna reach for just the regular index.html. So in this sense the way we match something in the cache, it's gonna look a little bit different.

[00:04:42] And I want you to pay attention to that part specifically. The easiest way, once we already have a list of resources to precache, the easiest way to go about adding index.html to that is to just push it right into this toPrefetch array, and we're done. Now I'm going to have to increment the cache version, just so that we get a fresh pass.

[00:05:10] Start the server up, and let's think about what we wanna do next. So, we're gonna need a little bit of logic in our service worker. And the suggestion I made as we were setting this exercise up was that we want to kinda just handle index.html cases and exit early.

[00:05:40]
>> Mike: So it'll look like this.
>> Mike: Handle it return, something like that. Remember, it's not important what we return from this function event. That respondWith, that is the main thing that's interesting here. So basically we're just gonna exit early in the even that we're handling this situation. And there's no special sauce here.

[00:06:05] These are just tools and rules of thumb for managing complexity, right? Cuz a lot is going on inside fetch at this point. Let's look back at the slides. So we have a couple little cheats here, couple of suggestions. The first is these two constants. So I'm gonna put those at the top of my service worker.js.

[00:06:29] That's gonna give us a URL for index.html. This is important because it's the key we're going to use when we reach into the cache. We might get a request that comes in for /orders, we're always reaching just for index.html. We kind of ignore the path because we're dealing with the single page up.

[00:06:48] The path is an illusion from an HTTP request standpoint, it's just that route page. So, the next thing we're gonna steal from here is our two checks. I gave them to you because the point is not to be tricky about this. And if you're like me, you probably keep cheat sheet of things like this.

[00:07:09] So less chance of bugs if you're just always are pulling it from the same place. You solve it once and then reuse it. Okay, if it's an HTML request, I'll just change that like here, actually, to align with the slides. And there's our request, so we have to add event.request.

[00:07:34] And if it's an HTML request and isLocal, so if we're not dealing with a Chrome extension or something. If you ever clicked on something in Chrome up at the top where it'll open up a little widget like this. That's an HTML document, you don't want to be dealing with in your service worker.

[00:08:03] And that's why we're doing isLocal. So, we have a bias for responding with the fetch first.
>> Mike: And the nature of most static hosting for single page apps is you can hit it with any path you want, and you're just gonna get the same index.html page back. So it's fine to do the fetch part of this a neat way that we've been working with all along, right?

[00:08:39] If you even pass /orders, if I were to curl that from the terminal, I'd still get HTML back, it's fine. Now, if we get a response, that's great.
>> Mike: If we run into a problem, we need to deal with it a little bit differently. So here, we're going to return, actually, I can try to do it, well, I'll do it like this.

[00:09:13] Return caches.match.
>> Mike: INDEX.HTML_URL, or INDEX_HTML_URL. So we're always reaching into the cache for that same thing. This is the only time we've done this, everywhere else we've passed the request object in. This is a unique thing about dealing with single page apps and caching in index.html. And the last thing is I want to specify which cache, and it's gonna be the prefetch cache.

[00:09:43] Cuz, remember, I added it to the list of toPrefetch, that array.
>> Mike: All right, shall we take it for a spin?
>> Speaker 2: Yes.
>> Mike: [LAUGH]
>> Speaker 2: Thank you.
>> Mike: [LAUGH]
>> Speaker 2: I thought someone else was going to say it.
>> Mike: I wasn't moving until someone-
>> Speaker 2: [LAUGH] I figured, I allow you to keep going.

[00:10:15]
>> Mike: All right, so here we go. We're online.
>> Mike: So I'm gonna to Application, there's a nice little check box here that lets us go offline.
>> Mike: [SOUND] I'm gonna stop my server.
>> Mike: And it still works, I'm gonna close code
>> Mike: And it still works. So we now have an offline application.

[00:10:51] Just keep in mind, I want you to understand how far we've come here. Keep in mind we haven't really touched all of the react stuff that you're seeing on the screen. And the big idea here is we have added offline support by putting something underneath the application rather than adding a whole bunch of complex sophisticated stuff that is entangled with our app.

[00:11:15] This is a separate project. Think of it that way, it's a separate project. Separate script that gets built. You can share modules, right? It's not even opened anymore. Although you have six modules and grab stuff, utility functions and whatever we need. But in the end we're left with two largely decoupled things that are working together.

[00:11:46] And if we took the service worker away, we'd be looking at the traditional offline-asaur, right? So pretty big idea.