skip to content

Create a PWA from Scratch

Progressive Web Apps get talked about a lot, but what *is* a PWA? In this episode, Patricio Vargas (pato) will teach us how to create one from scratch, including Service Workers!

Full Transcript

Click to toggle the visibility of the transcript

Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.

JASON: Hello, everyone, and welcome to another episode of Learn With Jason. Today on the show, we we've got Pato. Pato, how are you doing? Thanks for joining us.

PATO: Hey, thank you so much for having me. I'm excited to be here.

JASON: Yeah, I'm excited today. So, we're going to talk about something fun, but before we talk about what we're going to do, let's talk a little bit about you. For people who aren't familiar with your work, do you want to give us a little bit of an overview of yourself?

PATO: Yeah, for sure. So, basically, I'm a do it all. I'm a Google developer expert in Angular and web technologies, but I don't like to call myself an expert because I feel like there's always, like, room to grow and there's someone always, like, that knows better than you.

JASON: For sure. For sure.

PATO: So, I don't like that. I think the title should be renamed, like, Google developer advocate for whatever technology. But that's just my personal point of view. I'm a Senior Developer currently for a company called One Signal, a push notification provider and SMS messages and emails as well. We have several open‑source projects for React, Angular, React Native React Native, iOS, Android, and essentially every single device and tool possible. What else? I'm just a people person. That is the reason why I decided to change my career a little bit from just being a software engineer into a developer advocate.

JASON: Nice. Very nice. Well, cool. So, today, we are going to be talking about something that I think was popularized by Google, which is Progressive Web Apps. This is a term I heard thrown around a lot. People will say, oh, it needs to be a Progressive Web App or they'll use it as a description for building a modern app, but I've heard it used somewhat inconsistently, and sometimes I hear it used almost interchangeably with the idea of progressive enhancement. Or I hear it used as a description of, like, mobile friendly. And so I think that there's a little bit of confusion in the community about what a Progressive Web App actually is. So, maybe we can start with just a definition. What is a Progressive Web App?

PATO: A PWA or a Progressive Web Application, in my personal point of view, is an application with super powers. That's the way I like to describe it. You can do exactly the same as a regular web application, but since you're using some tricks that we're going to be talking about later in the stream, you can make your application go farther and have also these superpowers like ins stalled application on our phone, right? Caching strategies. Caching network. And just making your application extremely performant.

JASON: Okay. And is this the sort of thing that ‑‑ is there a check ‑‑ like, is there a true/false statement about Progressive Web Apps? If you hit these check boxes it is a PWA or is it more like a PWA is a state of mind? (Laughter)

PATO: I mean, I think it's kind of both. It's a state of mind. But definitely, for sure, there is a checklist. So, for you to have a PWA, for sure, you need three things. First of all, your web app, right? You don't have your JavaScript, you don't have your HTML, you don't have your CSS, you don't have an app, right? Second, you need a manifest that JSON is just a JSON file that has certain properties that tells the browser, hey, this is the icon of my Progressive Web Application. This is the icon you're going to use when you install the application on your device so it looks like a native application, right?

JASON: Got it.

PATO: The most important and coolest things about Progressive Web Applications are service workers. Service workers, in my personal point of view, they are the brain behind Progressive Web Applications.

JASON: Gotcha. That's very cool. So, a Progressive Web App is ‑‑ that's a short checklist. That makes me happy. I was worried that there was going to be a lot to it, right? So, this sounds exciting. A manifest tells a browser a little bit about what an app it is so it can display it properly and install it. A service worker gives it some extra brains and capabilities that we're going to look into more so you don't need to ‑‑ everyone at home, if you're panicking like, wait, let me Google that. Don't worry about it. We're going to show it today. Okay. So, maybe a good question here is, why would I do this? Like what's the benefit to me as a developer of taking the extra steps of creating the manifest and the service work?

PATO: That's a great question, and I can tell you probably a lot of reasons why, but I can think of a few. Accessibility, right? And what do I mean with accessibility? Let's go by steps. So, I'm just gonna give you, like, a personal story. Like true story. You know, it actually happened. So, I used to do consulting back in the day for a company that is actually fairly big, right? When I was doing consulting for that company, they were, if I'm not mistaken, in 70 countries, right? And they sold products online. The problem that this company was encountering was that the majority of their customers are in developing countries.

JASON: Sure.

PATO: I'm Mexican. I know one of the problems that we have in developing countries is internet connection.

JASON: Sure.

PATO: You know?

JASON: Yeah.

PATO: Or internet might not be super fast. Which means other people, you know, they just get tired of surfing the web and they just exit your application and they don't continue their workflow.

JASON: Right. Right.

PATO: With Progressive Web Applications, they're extremely friendly with offline, right? Meaning you can still use your web app if you are offline. You might be thinking, wait, wait, wait, what are you talking about, Pato? I need internet to have my web working, right? I know I might sound a little bit crazy, but it's true. So, basically, this is how it works, what I mean with accessibility. You have your web application. You make it a PWA, right? Now you can use caching strategies to make your application work offline, right? So, instead of every time that you open a website, making a request to the server, bringing in the images, the CSS, the, I don't know, the connection to the database and all that, you're not gonna keep doing that over and over and over. You're gonna do it one time and one time only, right?

JASON: Mm‑hmm.

PATO: So, the first time the user wants to access your website, they're going to need internet connection, but from there, they don't have to depend on internet connection all the time.

JASON: Got it.

PATO: So, I'm just going to give you an example. Let's pretend I was using the application for my previous client and I wanted to buy a pair of shoes. You know? And my internet connection wasn't very good. So, I could be thinking, oh, my God, I need to be, I don't know, somewhere in the city to have a better internet connection to purchase my shoes.

JASON: Mm‑hmm.

PATO: You don't really have to worry about that. I open the application the first time, things are cached, I went through the workflow of purchasing my shoes with the help of the service worker, because the service workers did the caching strategies, right? And maybe implemented as well the background sync API. The background sync API allows you to use your application the same way that if you were using your application offline. So, one thing is the service worker that helps you cache the assets and the network calls. One thing is the background sync API. There are two things. The background sync API, what it does is, hey, use your application like if you were online, but whenever you actually reach connectivity, the background sync API is gonna be aware of that and it's gonna make the service calls for you.

JASON: Yeah, so, it's sort of like ‑‑ it's sort of like I'm making a list of steps and then the background sync API is keeping that list of steps and then when it can, it executes those steps, but for me, they appear as if they're already done because I've, like, the app allows me to kind of keep moving through the flow?

PATO: Exactly.

JASON: Okay, cool.

PATO: So, I purchased my shoes, you know, and actually they're not fully purchased because there is the ‑‑ they're living ‑‑ the requests are living in the background for the background sync API to trigger. But, you know, in my head, I already purchased the shoes. I go and play soccer. Then I decide to go to the city in two hours or the next day, and then the background sync API gets triggered and like, hey, there is actually internet connection. So, I send the request to the server, right? So, that's product accessibility, right? Also, another way that you can think about accessibility in different countries or places that don't have full internet connection, you don't need the background sync API all the time. It depends on your use case.

JASON: Sure.

PATO: It's very complex, but it's very easy to make your application work offline with just service workers. Maybe just to give you an example, maybe you have a list of books, right? Maybe you have a web application that pulls a list of books and you want to maybe read a few of them. So, maybe you can even, like, cache that, right, and every time that you open your application, even if you're offline, you can read them.

JASON: Mm‑hmm.

PATO: So, you don't need to be pulling the assets and/or information from the database over and over and over. And that's actually a good practice that people should follow whenever they're working with any single web application. How many times has it happened, Jason, that you, you know, I mean, you have an application that you know everyone that uses that app is gonna be working online, right? You know, maybe at the corporate office.

JASON: Right.

PATO: Will they keep pulling this same data over and over and over and over. You know, those requests affect the performance of your application.

JASON: Absolutely.

PATO: Those requests, if you're using AWS or another tool that means that it's gonna cost you money every time that you make a request to the Cloud, right? So, you can avoid these kinds of things by using the caching strategies and service workers. Just to give you an example. Let's pretend that you are a professor, right, and you have at least 100 students. Most likely, your students are not gonna change throughout the semester, right? Unless, you know, they're like, oh, Jason's, like, super hard. I'm gonna drop this class, you know? You know what I mean. So, basically, what you can do is you can cache the network call that pulls information from the database that contains the 100 students, right?

JASON: Right.

PATO: And you open this application every day, but you're not going to be making the server call over and over and over. Maybe what you can do is change your caching strategy so that it expires after a week.

JASON: Sure.

PATO: In that week, it makes the server call again. So you can do that.

JASON: Great. This sounds really promising. I see some questions. Are we gonna work with the background syncing API today?

PATO: No, because that would require, like, four hours of streaming.

JASON: Okay. All right. Let me ask this question. Does the, like, what happens if the background sync API fails or times out? Does it do a bunch of retries?

PATO: It does retries, but what is a good practice to do is have, like, canned data, if I want to call it that way, or a message saying to people, hey, the sale didn't go through. We weren't able to make the server call or something like that. I mean, just a more user friendly message explaining to people what's going on.

JASON: Gotcha. Gotcha. Okay. That makes sense. All right. I think at this point, the easiest thing to do might be to actually dive right in and give this thing a try. So, why don't we switch over to the page here. So, I'm gonna go to this view. And you can see here that we've got live captioning happening on the homepage of the site. This is being done by Jordan from White Coat Captioning today. Thank you very much, Jordan. And that is made possible through the support of our sponsors, Netlify, Fauna and Auth0, all of whom are making the show more accessible to more people. You can watch that right on the homepage of the site. And we are talking today to ‑‑ if I can get to the right tab. This is Pato's Twitter. @devpato. So, you can go and give him a follow and get lots more insights. And is there a resource that you recommend people go to if they want to, like, get the overview of Progressive Web Apps?

PATO: Yes. I can share them in the livestream in you want.

JASON: Yeah, please do.

PATO: There's multiple things that I want to share. So, basically, I love Progressive Web Applications and I have tutorials for React, Angular, and just vanilla PWAs. Let me share that with the audience. Just as an FYI, Twitter uses PWAs. Their actual website is a PWA as well. Instagram, WhatsApp, Tinder, Starbucks. A lot of people are moving that way as well.

JASON: Nice. I see some greetings in Spanish. I was happy that I could understand that. My Spanish is bad, but apparently not that bad. (Laughter) Great. So, did you share links somewhere?

PATO: I'm pasting that right now.

JASON: Okay. Great.

PATO: There you go.

JASON: All right. So, here is a couple links we can share. Let me pull this up. Make sure these go into the show notes as well. So, here's one on introduction to PWAs. And then this is web.dev. Web.dev is one that I have seen before. And here's an overview of Progressive Web Apps. Okay, great.

PATO: If you're gonna look for everyone in the audience, if you're gonna look at a link, I would suggest you to look at the one from web.dev. It's from developers from Google and they're, like, way smarter than me. So, I recommend you to take a look to that one. And if you just want to learn more or just compliment your knowledge, take a look to my article then.

JASON: Great. Great. Great. Awesome. So, these will be in the show notes. Now, I am not gonna read these yet, because today, you're gonna be my tutorial. So, what should my first step be if I want to build one of these?

PATO: Okay. So, the first step is to create a web application. And what do we need for a web application? We need an index HTML.

JASON: Mm‑hmm.

PATO: We need a JavaScript file. And we need a CSS.

JASON: All right. So, let me get into this folder. I'm going to git init and then we'll open this up. Wow, that is huge. What was I doing? Okay. So, here's my empty folder. So, you said I need an index.html.

PATO: Correct.

JASON: I need a CSS. And what else did I need?

PATO: And your index.js.

JASON: Index.js.

PATO: So, those are the basic components for a web application. Now, we need the basic requirements or the basic files to make your web app a Progressive Web Application.

JASON: I'm setting up the very basics here.

PATO: The very basics. Yeah, no problem.

JASON: All right. So, let's do a script tag. And I'm going to bring in index.js. And okay, all right. Here's ‑‑ okay. So, there is our app. All right. And if I run this, it looks like we can run this a handful of ways, I'm just gonna use Netlify dev because I use it all the time because it just makes things work. All right. So, here's this app. Let me get this over here. And then I'll minify that. That's a whole other thing. If you want to know what that is, watch Prisma Serverless. Here is the app running. If I look in the network tab and refresh, styles.css which is empty and index.js which is empty. They're both loaded without errors. That is good. I can close that because we don't need that query string. All right. So, here we go. We got this thing going.

PATO: So, go back to your code editor, please. And then the first step will be to create a manifest.json file in the root of your folder.

JASON: Okay.

PATO: Beautiful. So, now we are gonna navigate to ‑‑ I want to show people where can they get this structure, right? This is actually boilerplate. It's not gonna change all the time.

JASON: Ah, perfect.

PATO: What you can do is go to the Progressive Web Apps website. That one right there. And scroll down. And let's look for the manifest. So, right there, as you can see, exactly. Click on that one. Shout‑out to those people who wrote this. So, that's awesome. So, copy that code. And we're gonna go through it in a second.

JASON: Okay. So, let's take a look at what we got here.

PATO: Yeah. So, this is boilerplate code. It's always gonna be the same, so please don't try to memorize this. Just copy‑paste it. Basically, the short_name is the name that your application is gonna have. The icons are gonna differ based on the size of your screen.

JASON: Mm‑hmm.

PATO: So, for this example, we're not gonna use all the icons, right?

JASON: Okay.

PATO: Let's do maybe, I don't know, maybe we can do, like, two just to show some examples.

JASON: Okay.

PATO: So, do the 512 ‑‑

JASON: I should have something in here that we can use. Let's ‑‑

PATO: Awesome. If not, I can send you something, too, as well.

JASON: Let's see what I've got. I'm sure I have some nonsense in here. Here's the Learn With Jason design files. And I probably have ‑‑ where are my ‑‑ here are my emoji. One of these is gonna work. How about this? We'll make this into our setup. So, I can export this as a PNG.

PATO: Mm‑hmm.

JASON: And you said 512?

PATO: Yes, sir.

JASON: Okay. So, we'll go 512. Then we also want to export it as ‑‑ did you have a different size?

PATO: Yes. Let's do 192 as well.

JASON: 192. And we'll call it "192." We'll call this one "512." And PNG is okay or do you want a different?

PATO: No, PNG is perfect.

JASON: Okay. So, let's export. Come on. We're beach balling. Wait. You can do it.

PATO: Fingers crossed.

JASON: I have about a billion things running on this computer and it's an old one. This is definitely not an M1. Come on.

PATO: You need to tell Netlify to sponsor you the new M1.

JASON: I know. All right. Let's see if I can try this one more time. Okay. Let's try this again. I'm gonna export. Exporting. Do the thing. Do the thing. Oh, no, I don't think it can do the thing. All right. Let's see what I have on my computer that might work. I'm gonna search off screen because I have no idea what's on here. Let me just see if I have something at 512. Name matches 512. Nope, don't see anything there. Let's look for a JPEG. Here is ‑‑ I gotta have something in here, jeez.

PATO: I can get you one really quick. Um, give me one second.

JASON: Let's go ‑‑ I got something in here.

PATO: You got it?

JASON: I got to have something in here. You know what? This is gonna work. So, I've got this SVG.

PATO: Mm‑hmm.

JASON: And we can just use that, right?

PATO: I haven't used SVGs before with the manifest.json.

JASON: Oh, wait, I just found some PNGs. What size are these?

PATO: Oh, there you go.

JASON: I have no idea what size these are but they should maybe work.

PATO: Yeah, they should work.

JASON: We'll just make this work then. Okay. So, here is my PNG. It says that it is 512. Okay. Perfect. So, let's go ‑‑

PATO: Jason, copy the name.

JASON: Okay.

PATO: Beautiful. Now go back to your manifest.json. And there you go. Just change ‑‑ replace the source for that one right there.

JASON: That one. Let's see if one of these other ones is a different size. Are you different? No, these are all the same size. Can we just use the one? Is that okay.

PATO: Yeah, let's use the one for 512. That's perfect. And then, okay, we have the icons. So, remember, guys, the icon is the icon that is gonna be shown in your mobile device whenever you installed the Progressive Web Application. So, the start URL is essentially telling the ‑‑

JASON: Like the icon ‑‑

PATO: The browser. Where is the starting route, right? So, for this case, just erase the question mark and source equal to pwa, just leave the back slash.

JASON: Homepage by default.

PATO: Yeah, exactly. And then the background, right? So, every time that you have an application, right, you have different things on the manifest. You have different colors, right? So, if you take a look to the theme color and the background color, there are different things. So, the background color ‑‑ let me pull that up really quick. Because I was getting confused. There you go. Let's see. Let's see, background color.

JASON: Let's see, where's the theme color down here?

PATO: So, the theme color is the bar. So, every time that you install an application, right ‑‑

JASON: Mm‑hmm.

PATO: ‑‑ the navigation bar is going to have a color. That navigation bar can be blue, white, black, orange, or however ‑‑ in this case, you can just leave it as it is. So, that's the theme color, yes.

JASON: Okay. And so the ‑‑ and the background will be the splash screen. This will be the bar.

PATO: Exactly.

JASON: Great.

PATO: So, whenever you are installing the application, there's gonna be a splash screen and it's gonna be the background color that you assign.

JASON: Got it. Okay.

PATO: What else do you need to know? Standalone is the orientation of your screen. Standalone is the default one and the most common practice one. Leave it as it is. There are other displays, properties that you can use, but the problem with those ones is that it affects accessibility.

JASON: Got it. Okay.

PATO: So, people that have, you know, reading issues or something like, it can be more complex for them to use a Progressive Web Application, so just leave it as it is.

JASON: Got it. Got it. Okay. And then scope is, like, that's if I wanted this to be, like, dashboard was my PWA and your start URL would be dashboard. I could change my scope so that it only tried to use the dashboard?

PATO: Exactly.

JASON: Got it. Okay.

PATO: So, now in the ‑‑ let's see. Shortcuts. Let's see if you should ‑‑ you don't need all that. Just for the time, just erase everything from shortcuts all the way down.

JASON: For all of it, we don't need any of it?

PATO: That information is basically for you when you load your PWA into a PWA store, right?

JASON: Oh, I gotcha. I gotcha.

PATO: To be more descriptive. Just for the sake of time, we're not gonna do it. Be mindful that there is such a thing. The same way that you have a native application, it requires screenshots and it requires a description. Same for a PWA. Whenever you want to load it into a PWA store.

JASON: Got it.

PATO: Awesome. So, we have the manifest.json. Beautiful. Now go back to your application.

JASON: Okay.

PATO: But in the server. Whenever you were, like, running it in the browser.

JASON: Where was I doing that? Here.

PATO: There you go.

JASON: Okay. Sorry.

PATO: Is that doing hot reload or not?

JASON: It's not ‑‑ I mean, no, but I just refreshed the page.

PATO: Okay. Awesome.

JASON: And if I go to manifest.json, it's there.

PATO: There you go. Beautiful.

JASON: Now, we're not linked to it or anything.

PATO: So, what we have to do is link it. So, go to your index HTML page, please. And we have to let the web application be aware of the manifest.json. So, instead of your head, you're gonna open up a link tag and then you're gonna ‑‑ oh, there you go. Auto complete. Love it.

JASON: Yeah, VS Code makes this very easy. So, you know, if you just start typing link and it asks you what you want. Oh, hey, look, that looks right.

PATO: Awesome.

JASON: Very handy.

PATO: Perfect. So, now we have successfully linked ‑‑ well, hopefully. Yeah, if you go back. How can you test if this has linked properly? What I want you to do, Jason, is please open up Google Developer Tools. And you're gonna see a tab that says "application." Click in there. And if you scroll ‑‑ oh, there you go. Click on the manifest file all the way to the top. And if you scroll down, I mean, it has been successfully linked, right? You can see the theme color, the background color. Scroll down, all the way down. And there's your icon.

JASON: Nice. Great.

PATO: So, those are the basic things that you need for manifest.json. So, now let's get into the more complex and the more fun part, in my personal point of view, which is using the service worker.

JASON: Okay.

PATO: As you can see, under the manifest tab, on your left side, there's another tab that says "service worker." If you click on it, there's nothing there. Why? Because we haven't installed the service worker in our application. So, why don't we go ahead, Jason, and create one service worker.

JASON: Okay. I'm creating a new file. Does it need to be called something in particular?

PATO: You can name it however you want. There's two names that usually people name their service workers. Either service worker.js or sw.js.

JASON: Okay. We'll go for description like that?

PATO: That's perfect.

JASON: Okay.

PATO: Now, what we need to do is ‑‑ okay, we have that. And we need to, first of all, let your application know about the service worker, right? We need to make it aware. Just as an FYI, the JavaScript service workers are not regular JavaScript files.

JASON: Okay.

PATO: That's something you have to be aware of. So, the service workers, they live in the background of your browser, right?

JASON: Mm‑hmm.

PATO: They do certain things that regular JavaScript files don't perform. For example, a service workers has the ability to receive push notifications in the background, even if you don't have the service open.

JASON: Okay.

PATO: It's completely different. The first thing we have to do is let the application know about the service worker. If you go back to the index.js file.

JASON: Index.js?

PATO: Mm‑hmm.

JASON: Okay.

PATO: That file right there is actually our ‑‑ I'm sorry, the application is just like any other JavaScript file, right? No problem. So, what we have to do here is, first of all, we have to link this index.js file with your application, which is gonna be happening in the index HTML.

JASON: That part is already done.

PATO: Okay. You did that already? Awesome. Let's just test it out.

JASON: Let's double check. Here we go. So, our JavaScript is loading.

PATO: Awesome. So, we need to register the service worker? How do we do that? Then you're gonna type service worker in quotation marks.

JASON: Like that or capitalized?

PATO: Just like that. I'm sorry, you're gonna capitalize the "S" and the "W".

JASON: Okay.

PATO: No, I'm sorry. Just the "W". Go back to the "S" and leave it the way it was. Yes. There you go.

JASON: Okay.

PATO: And then you're gonna do in navigator. Now, let's talk about this line. Essentially, what this line is doing is, hey, the service workers are available in my navigator and in this browser, then let's go ahead and use it, right?

JASON: Mm‑hmm.

PATO: So, now, what we need to do is if it's true, right, meaning that you're using a new browser, you're gonna do window, which is reserved keyboard.

JASON: Okay.

PATO:  .addEventListener. You're gonna open up quotation marks and in parenthesis, you're going to write load and then comma. There you go. You're faster than me. You're like Vim. Inside of that, you are gonna type navigator.serviceWorker ‑‑

JASON: Okay.

PATO:  .register. Inside the app, open up parenthesis. Quotation marks. Then you're gonna type the name of your service worker. FYI, everyone in the audience, it's good practice to have your service worker living in the route of your project. You can only have one service worker.

JASON: Can you talk a little bit about why? I feel like this is a gotcha that people don't know about until it bites them.

PATO: So, for some reason, don't ask me why, the browser only detects one service worker per application, right? There's some people that have more complex workflows and they're required to have more than one service worker. Jason, what do I do now? I need to have three service workers. What do I do? No problem. You can actually combine them into one. You're still gonna have three separate files and let's say import two service workers into one and have one single source of truth.

JASON: Mm‑hmm.

PATO: And then you will just work with one service worker.

JASON: The other part about this, something that threw me, why do we have to put it at the route? Why can't I put it in my assets service worker file?

PATO: You can put it anywhere, but it's the best practice to have it in the route. If you're going to change where the service worker is going to be living ‑‑

JASON: So, I was under the impression that the service worker had to be at the highest level that the ‑‑ that it had to scope to, right? And, like, so, I was led to believe that in order for the service worker to actually cache resources at the route, the service worker had to be at the route. If you put it in an assets folder, it would only be able to affect anything in the assets sub path.

PATO: I could be wrong, but I'm 90% sure you can change that.

JASON: It's been a while since I've looked at this. It's entirely possible things could have changed.

PATO: I could be wrong. Always open for feedback. Not a good practice because you have to, like, most of the people bring the route.

JASON: Gotcha.

PATO: And the reason why I'm saying this is because I was working in a plug‑in for installing push notifications into your device.

JASON: Mm‑hmm.

PATO: Right, using WordPress. For some reason, WordPress was requiring us to change the scope of the service worker. So, I had to figure out how that worked. But wait ‑‑ scratch that. No, it has to live in the route. And now I remember, it has to live in the route, but all your other service workers, they can live somewhere else.

JASON: And you can import them?

PATO: Yes, exactly. 100% right.

JASON: And the reason for that is security, right?

PATO: Well, can you tell us more about that?

JASON: Yeah. So, basically, because service workers are really powerful. Like you can ‑‑ you get to proxy things. You get to catch all the data come in and out. You can do all sorts of stuff with service workers that if somebody was trying to be evil, they could be real evil with service workers. So, in order to prevent, like, somebody who has a customizable profile from uploading a service worker at yoursite.com/their profile name and put in a service worker and take over a whole website because service workers would let them do that if they can go up a level. This would scope them to only their subdomain, sub path of username. Ideally, you wouldn't let people upload a service work tore any app that you had them on. This could also be useful if you're using proxy domain. You've got multiple apps and each of those apps is being served at slash home slash dashboard slash account, right? Each could have one scoped to slash account or slash dashboard which would do things like make it work offline, but they wouldn't be able to, like, the dashboard team couldn't accidentally break the account team's UI by having their scope leak. Because they're limited to just the one sub path that they're in. That's why service workers have to live where they are. They can't actually go up levels in scope.

PATO: That's awesome. I didn't know all that information. That explains why web flow doesn't allow you to load service workers.

JASON: Yes. Exactly. Anything that's in a sub path is essentially a ‑‑

PATO: A risk.

JASON: The way they mitigated that risk is saying you can only be in your own sub path. You can't be up level from a service worker.

PATO: Awesome. Want to continue?

JASON: Yeah, let's do it.

PATO: So, the first thing you need to know about the registration of your service worker is actually a promise. And what do we need to do with promise? We need to trigger them, right? You ‑‑ that's up to you. You can do it the async way or just do it ‑‑

JASON: Let's do one of these because it's a little cleaner to write.

PATO: Yeah. Sounds good.

JASON: Do I need to store it?

PATO: No, you don't.

JASON: Okay.

PATO: And if you want, just, you know, you have the ‑‑ your service worker. Because we're not gonna do anything else with the service worker. In this case, we're only gonna register.

JASON: Okay.

PATO: So, that seems correct to me. So, why don't we go ahead and test it out.

JASON: Okay.

PATO: So, right there, the service worker, you know, just write ‑‑ do console log and then service worker.

JASON: Okay.

PATO: And then save it. And let's re‑run our application. There you go.

JASON: Okay. So, it logged.

PATO: It logged. Now go to application. And the service worker, you can see that it's active and it's running. So, if you see that status as green, that's beautiful. You're in good hands. So, now let's talk about the things that you can do with service worker, right? So, like we were saying, you can cache.

JASON: Right.

PATO: So, why don't we do some caching.

JASON: Yeah, let's do it.

PATO: Go back to your index.html file. Just do me a favor. Just add a random image. Maybe you can use the same one from the icon.

JASON: I have ‑‑ I have some links here. Yeah, let's do one of ‑‑ let's do one of these. Here's a picture of me on a stage.

PATO: Look at you.

JASON: And so we can go open this. And that's a big image. Do you want me to save it locally?

PATO: Yes, please.

JASON: Okay. So, let's save the image. And we're gonna go to GitHub. Learn With Jason. Here. And we'll save it. All right. So, this image is huge. This is going to be ‑‑ because that's, like, the full size, uncompressed image. So, if we look at ‑‑ in here, it's 913 kilobytes. It's a big image.

PATO: Yeah, it's a big boy.

JASON: Unoptimized, uncompressed for whoever needs it for trolling or whatever.

PATO: Awesome.

JASON: There we go. We've got that. I'm gonna change the ‑‑

PATO: The name.

JASON: The name just to be something easier for me to type. Just call it Jason.jpeg. And then let's load that up in here. And we can go with Jason.jpg. And we'll add some alt text.

PATO: Because we care about accessibility.

JASON: Absolutely, we do. All right. So, now we've got an image. And that ‑‑

PATO: Beautiful.

JASON: ‑‑ if I come out here, should show up. Oof. All right. Can I do a little bit of CSS just to clean this up?

PATO: Yeah, of course.

JASON: All right. So, let's go with HTML and body, we'll go with ‑‑ I've got this shortcut here to make that happen. And then ‑‑

PATO: Nice.

JASON: ‑‑ I can go with image and we'll go with max‑width of let's call it 600 pixels. And that should, yeah, a little bit less ‑‑

PATO: Beautiful.

JASON: ‑‑ jarring to look at.

PATO: Awesome. So, now, why don't we go ahead and use the service workers to cache some of our assets, right? Let's go ahead and cache the index HTML, the CSS, the JavaScript, and your image. So, the first thing that we have to do is to name or cache, right? Let's give it a name. So, write const.

JASON: Const?

PATO: Yeah. And then maybe you can name it cache name.

JASON: Cache name.

PATO: =, and then just do like Jason V as in Victor and 1.0 or something like that.

JASON: Okay.

PATO: There you go. So, that's gonna be your cache name, right? So, the next thing that we have to do is tell the cache what are the files that we're going to be caching.

JASON: Mm‑hmm.

PATO: And if it's multiple of them, we're gonna have to use an array.

JASON: Okay.

PATO: So, why don't you create an array of files to cache. Yeah, that's perfectly fine. And then I want you to ‑‑ exactly. Yeah. Those are the files that we're gonna be caching today. Everyone in the audience, so, it's gonna be the index, the style.css, index.js and the image that Jason uploaded.

JASON: I can do this. Multi‑cursers. Here we go. Oh, no, I've made it so much worse.

PATO: And they have to be in quotation marks.

JASON: This got so bad. I was like, this is gonna be great and then couldn't remember how to do it. Okay. Here we go. Here is our list of files. Let me just double check I got all all of correct. Yes. Okay. Okay.

PATO: Beautiful. So, now, the service worker ‑‑ well, the service workers in general, they have life cycles, right?

JASON: Mm‑hmm.

PATO: The first thing that you have to do with a service worker is register the service worker.

JASON: Okay.

PATO: The second one is to install the service worker. And during the process of installing, you can do some caching, right?

JASON: Okay.

PATO: So, do you want to do that?

JASON: Yeah, let's do it.

PATO: Awesome. So, the first thing that we have to do is use the word "self." And then .addEventListener.

JASON: Okay.

PATO: And we're gonna use install because we're in the life cycle of installing the service worker, right? And then you're gonna do ‑‑ yeah. You can do that. But instead of the parenthesis, I want you to put the word "event."

JASON: Okay.

PATO: Beautiful. And then you're gonna do ‑‑ just to make sure that we're in the correct process of installing, do a console log that says "install service worker" or something like that.

JASON: Okay.

PATO: Nice. And then a new line. And you're gonna do event.waitUntil. Until is gonna be capital U. There you go. And inside of that, you're gonna have a parenthesis. And what I want you to do is open the cache, right?

JASON: Okay.

PATO: So, use the reserved keyboard caches.

JASON: Here?

PATO: Yes.

JASON: Okay. And then .open ‑‑ no ‑‑

JASON: Wait, I'm confused.

PATO: Yes. Erase everything inside of the parenthesis. There you go. And then caches.open.

JASON: Like that?

PATO: Just like that.

JASON: Oh, it's not a call back. Okay, I got confused.

PATO: No, it's not a call back. So what are you telling your web application right here is, hey, open up my cache. But which cache, Jason? Which cache are we opening?

JASON: Well, we need to open this one, but we're not 100% yet. So, do I just drop that in here?

PATO: Let's open that one.

JASON: Ah, I understand. Okay.

PATO: And then that's actually a promise, right? And once again, what do we need to do with promises? We need to trigger them. Yes. You can do the sync.

JASON: Here or caches?

PATO: Da‑Da‑Da‑Da‑Da. Caches is the one that is in the promise. Yeah, so, if you want, yeah ‑‑ and where else we need to do? Oh, yes. Now we need to specify ‑‑ you can ‑‑ I'm sorry. Okay. We have a way caches open, cache name, and you're gonna store that inside of a variable. And you can name it "cache" if you want. So, you're gonna have to open up curly brackets for that.

JASON: Like this kind of thing?

PATO: Yes. Mm‑hmm. And don't forget to declare the const of your cache.

JASON: Okay. Like that?

PATO: Yes. Okay. Let me make sure everything looks good.

JASON: Wait, this one needs to be async then, not this one.

PATO: Correct. Yes.

JASON: Got it. Okay. I was confused. I'm not confused anymore.

PATO: Okay. Perfect. My bad. What do we need to do now? So, we have opened up the cache.

JASON: Mm‑hmm.

PATO: And now we have to tell that cache what files are we storing. So, the cache has a method called addAll, right? In this case, we are going to be using that one because we are going to be passing an array. Jason, can you tell me what array we're passing?

JASON: Is it just this one straight up or do we need to do something to it first?

PATO: It's just that one. And then you're gonna save that. And I think that looks correct to me. What do you think?

JASON: I believe you. (Laughter)

PATO: Okay. Fingers crossed. So, everyone in the audience, please cheer us on. So, now, save your file and open up the browser. Refresh the page. Let's see if this worked. And ‑‑

JASON: Okay. So, now do you see what's happened here? Can you talk a little bit about this?

PATO: Yes. That's another ‑‑ that's another life cycle. So, basically, we have to complete the life cycle of the service worker. Good call. So, why don't we go ahead and complete the life cycles.

JASON: And I do that just by loading the page again, right?

PATO: Refresh. So, no.

JASON: No!

PATO: So, go back.

JASON: Okay.

PATO: So, we need to activate the service worker, right? So, once again, at the bottom of the page, yeah, just create a new line. And do self once again. .addEventListener. And then we're gonna use the activate life cycle and just do it ‑‑ exactly. Inside of quotation marks. And then we're gonna do an event as well, like we did in the other one.

JASON: Okay.

PATO: This is a very, very cool life cycle. And the reason is for of the following. Most of the people use this life psych toll clear their cache, right? You know, it's gonna happen that maybe right now we only are caching for files, but maybe in the future you want to cache 5 files or something, right?

JASON: Okay.

PATO: And you want to change the name of your cache because it's good practice. You can see we have version 1.0. Maybe later on it's going to be version 1.1 or 2.0 and so on. So, what we need to do is remove old caches, caches that are not being used.

JASON: Okay.

PATO: So, once again, we're gonna use the key word caches. Remove that in line 15. Caches.keys. And open up parenthesis. This is gonna be a promise as well. So, let's go ahead and do the sync and await.

JASON: So, this is gonna be keys, right?

PATO: Um, yes. And Da‑Da‑Da‑Da‑Da. Okay. Perfect. And now what we need to do is ‑‑ so, that is returning you a promise, right?

JASON: Well, it shouldn't be a promise anymore, right? Because I awaited it. It should be an array of keys.

PATO: Correct. And now what we need to do is iterate through all the promises.

JASON: Whoops.

PATO: Right?

JASON: Keys. ForEach?

PATO: You can do forEach. Yeah, that's fine.

JASON: Okay.

PATO: And then what you want to do is compare ‑‑ you're gonna compare the ‑‑ each key, right, that you have in your cache with the cache name, right? So, basically, this is what we're doing. If you want to just wait a second. So, what we're gonna be doing is comparing the names of the keys, which is everything that you have inside of your cache, with a cache name, right?

JASON: Right.

PATO: If it it's not different, right ‑‑ I'm sorry, if it's different, then you're gonna remove that specific key from the cache. You're gonna remove it. So, let's go through that again. Let's pretend that I have a cache named 1.0 and I have a cache named 2.0.

JASON: Mm‑hmm.

PATO: That means that my cache 1.0, it's old.

JASON: Right.

PATO: So, I'm gonna remove that cache if it's different, and I'm gonna keep the new one, right? So, what we need to do is instead of doing keys = =, you can do if it's different. If it's not equal.

JASON: Okay.

PATO: Right? And then you're gonna do ‑‑ Da‑Da‑Da‑Da‑Da. You're gonna do return.

JASON: Return?

PATO:  .caches. I'm missing something. Hold on. I'm missing something. Okay. So, here's a problem. A problem is that every time you're doing this, it's a new promise, right? So, we actually ‑‑ have you used a promise.all method? For those who don't know, a promise.all essentially grabs a group of promises and returns a single promise.

JASON: Okay. So, we can move this up here.

PATO: Mm‑hmm. And then caches.

JASON: And then I can do this. Is it, like, delete?

PATO: And then cache.delete. And yes. And why are we using delete? Because delete is a method that erases key values from an object. Right?

JASON: And so the reason that this is important is that, like, if ‑‑ as I'm asking you to cache things for my web app, the browser's not gonna give me unlimited storage, right?

PATO: Right.

JASON: And also, it's kind of a jerk move to say, hey, store megabytes of my old resources that I'll never use again on your machine.

PATO: Yeah. Yeah, that's perfect. So, okay, that looks correct.

JASON: Mm‑hmm.

PATO: Now, at the bottom of your activate ‑‑

JASON: Like down here?

PATO: Yes.

JASON: Okay.

PATO: Right there. What I want you to do is do event.waitUntil self.client.claim. Let's talk about that really quick.

JASON: Self.client.?

PATO: Claim. Open and closed parenthesis

JASON: Does this need to be a callback? This one?

PATO: Scroll down. No, it should be like that.

JASON: Okay.

PATO: So, let's talk about what the clients.claim is. So, they make your service workers take control of the page when you first register the service worker. If there is already a service worker on the page, it will make no difference. So, basically, now your service worker thinks that this line is gonna be taking control of your app, right? And so, yeah, now want to test it out?

JASON: Yeah, let's test it out.

PATO: Fingers crossed. Da‑Da‑Da‑Da‑Da. Okay. Let's do something. Click on "storage."

JASON: Storage.

PATO: On the left side. And then click on clear site data. The service worker, the old one is taking control. So, now refresh your page.

JASON: Okay. Activated and is running. And I have an error.

PATO: Okay. Let's look at that error.

JASON: Cannot read properties of un‑defined reading claim.

PATO: Okay.

JASON: So, that's this one. So, client is un‑defined.

PATO: Oh, it's clients.

JASON: Clients.

PATO: Yeah, my bad. My accent.

JASON: No worries. Let's try that again. Okay. No errors this time. It installed. But 976 is not ‑‑ 976. Oh, but we got errors again. What do we got?

PATO: Let's click on that error.

JASON: Failed to execute. Wait until the event handler is already finished and no promises are outstanding.

PATO: Okay. Let's see. Let's debug this. Okay. So, line 25 is not giving us an error anymore, right?

JASON: I think it is.

PATO: Oh, yeah.

JASON: It's line 25, but now it's the waitUntil. So, am I supposed to not call this?

PATO: No, you're supposed to call that, yes. Let's see. I think our problem is ‑‑ okay, caches. We got a promise.all. Yes. We got a keys.‑‑ then I'm checking if my cache is not the same. Right. Given that waitUntil. FYI, guys, this is why people don't like service workers, because you can make a mistake very easy. That's the reason people use Word Box, which we can talk about later on. Okay, this is fun. Okay, so. Let's see.

JASON: Are you sure it doesn't need to be a callback? I feel like ‑‑ I feel like it's yelling at us because we're not doing this inside of a callback. Because the error that it's giving us is it's not receiving a promise.

PATO: Okay. Let's test it out.

JASON: Okay. Let me just do a ‑‑ let me do one of these.

PATO: This is the cool thing about pair programming. Because we don't remember everything from the top of our head.

JASON: Okay. So, I am gonna clear the site data, and then we're gonna come back in here and run it again. It installs and it doesn't like ‑‑ it still doesn't like this. So, it's ‑‑

PATO: We have one error now, instead of two. That's a winning.

JASON: What's up, Alex. Thank you for the raid. Welcome, everybody. We are debugging service workers.

PATO: Okay. Oh, wait. Do we have the wait cache ‑‑ uh‑huh. And then ‑‑ hmm. Trying to see ‑‑ let me look it up. Maybe activate service worker. I don't remember everything from the top of my head. So, okay.

JASON: Let's see if we can get into ‑‑ I'm just clicking around through resources here on web.dev. Which is very powerful. And looking for ‑‑ boy, there's a lot of ‑‑ there's a lot you can do with this.

PATO: Yeah, it's insane everything you can do with service workers. Let's see. Let's see. Let's see.

JASON: You got something to try?

PATO: Um, so, let's see. I want you to go back to web.dev.

JASON: There's a question, does it need to be self? Can it just be clients.claim?

PATO: Let's see. Self. We're passing ‑‑ I mean, I don't remember everything from the top of my head, but it should be self.

JASON: Okay.

PATO: But I want you to scroll all the way to the top.

JASON: All the way to the top?

PATO: Yes. And then maybe let's try to use their search and type "activate service worker," and let's see what it gives us.

JASON: Think this one will help us?

PATO: Yeah, probably. Let's see. Let's take a look at that one.

JASON: Okay. So, let's take a peek.

PATO: Okay. Scroll up. Do you see where it says "activate" right there? Let's click on that one and see where it takes us. Okay. It's talking about the claims. Uh‑huh. That's good.

JASON: Should we pop into this and just look at the code?

PATO: Sure.

JASON: All right. An image will appear here in 3 seconds. Yeah, but how do I see the source code? If I want to see ‑‑ somebody remind me, how does Glitch work? If I go here and here maybe? Nope, that's not it. Can I just search for a project name? Yes, this is the one. View source. That's what we were looking for in the first place. Now this is such a fun thing. Do‑do‑do. All right. I want to see my service worker. No, but I want to see the service worker code. All right. So, on activate, clients claim.

PATO: Oh, they're using claims, okay.

JASON: So, do we even need to wait? Can we just ‑‑ like. Whoa, what did I just do. Let's do one of these.

PATO: There you go. Let's try that out.

JASON: All right. Let's try this out. So, I'm coming out here. I'm gonna clear this service worker again. Just get it out of here. And then we're gonna try this, refresh, activate and running.

PATO: There you go.

JASON: Aha! And now we should see, did it cache?

PATO: Let's see. Now, no, it didn't cache. So, click on ‑‑ do you see where it says "cache" on your left?

JASON: Cache on my left?

PATO: Yeah, you don't have anything cached. So, let's try to debug why it's not caching. So, that should be a problem instead of your install, right there. So, okay, we have the ‑‑ we have the event.waitUntil. Okay. That seems fine. We're opening the cache, right? Oh, wait. No. Yeah, we have the waitUntil. That seems correct to me.

JASON: Okay. Should we ‑‑ should we peek at more of these demos and see what they're saying?

PATO: Yeah, sure. Let's see. Go back to the ‑‑ maybe they have something there.

JASON: So, this one doesn't show that.

PATO: They had the one for the install right there. And where they're caching things.

JASON: Mm‑hmm.

PATO: Okay.

JASON: This one caches.

PATO: We have that. And that is a promise.

JASON: Cache.add.

PATO: Which in your case, we're using cache.addAll.

JASON: Cache.add and cache.add. So, I'm wondering.

PATO: They're using .add instead of .all because it's just a single file.

JASON: Yeah, I'm actually wondering if maybe we should go with their setup here instead of doing it as a ‑‑ instead of doing it as a ‑‑ yeah, as, like ‑‑

PATO: Okay.

JASON: Because I've never tried it.

PATO: Yeah.

JASON: Try it like this. Okay. And then let's go back out here and try again. And this theoretically should ‑‑ okay, now it doesn't like ‑‑ missing things on line 7, I forgot one, two, ah, three. There we go. All right. Try it one more time. Okay. So, this ‑‑

PATO: And now it's working. The cache.

JASON: 94 is activating and running, but it doesn't like ‑‑ that's okay. Let's go look at the application memory. Storage. Hey! No, wait.

PATO: Check this out ‑‑

JASON: Cache storage, yeah, yeah, yeah.

PATO: If you go to your left where it says "caches", expand it. Image.html.

JASON: This is cool. So, check this out. So, now if I clear this and I refresh, then it shows each of these came in. Initiator other. If I refresh, does it show service worker? Did I do a thing that, like, turned this off? Because I definitely might have.

PATO: It turn off what?

JASON: The caching part. Because it's not actually showing that it was loaded by the service worker. Do we have to check the fetch and, like, return from the cache to get it to actually show up?

PATO: Yeah, so, let's do something else. That's another life cycle of service worker, which is interesting that you talk about fetch, right? Which is a caching strategy. So, what we can do is, for example, we can check if things are cached, right? And if they're cached, then I want to return that file from the caches that are from the server. If it's not cache, let's hit the server. So, right there, you can just type "enter" and do me ‑‑

PATO: Someone is telling me that disabled cache is disabled.

JASON: Right. That's ‑‑ this would make sure that we didn't get anything from the cache. This should allow the cache to actually work.

PATO: Okay. There you go.

JASON: And so, yeah, right now, it's not, like, nothing is caching whatsoever. So, we want the service worker to pick that up. And currently it's not doing that. So, let's make it do it. So, we've got this fetch. And I'm gonna check the ‑‑ is it an event again?

PATO: Yeah, you got it.

JASON: Okay.

PATO: And then we're gonna use the event.responseWith ‑‑

JASON: Oh, respondWith like that?

PATO: Okay. RespondWith. Let me remember. And then this ‑‑ you're gonna use async this time. And then open up parenthesis. And then fat arrow. There you go. And then let's do const resource = await ‑‑ one second. We're gonna use the reserved keyword caches.match. And you're gonna do event.request. We're gonna talk about that in a second. And then ‑‑ okay. So, essentially, what's happening is, hey, let's pretend that, Jason, you're bringing up your image, right?

JASON: Mm‑hmm.

PATO: Your picture. So, that's a request, right? Every time that you're bringing something from the network is a new request.

JASON: Right.

PATO: Find that request inside of the cache. Now what we need to do is check if the resource came back, right? So, do if resources ‑‑ resource. I'm sorry. And then return resource. So, if it was found in the cache, we are gonna be using that one.

JASON: Right.

PATO: But now ‑‑ I'm sorry?

JASON: Sorry, I was just agreeing with you.

PATO: Okay. And now what we need to do is ‑‑ what happens, Jason, if the resource wasn't found in the cache?

JASON: Then we need to actually fetch it.

PATO: Exactly. So, let's do const response = await. And then fetch and then we can do event.request. And then return the response this time.

JASON: Okay.

PATO: Does that make sense or am I being crazy?

JASON: This does make sense. So, if we have it cached, return the cache resource. Otherwise, get it like normal and return that. So, theoretically speaking, when we go back in here and we go to our service worker and we make sure that it works the way we want it to ‑‑

PATO: But go back.

JASON: Did I forget to save this?

PATO: No, you are missing ‑‑ in line 23, right, you have ‑‑ okay, you have the response keyword. Uh‑huh. You need to ‑‑ okay. You're missing something right there. Let me try to remember what it is. So, on line 23, after that parenthesis ‑‑ I'm sorry, inside of that parenthesis, you are going to have to ‑‑ I think we're gonna have to execute this as well. Let's see. Let me try to remember. So we have the async await. We have the curly bracket, right?

JASON: Mm‑hmm.

PATO: And then you need the ‑‑ mm‑hmm. Okay. And then you're gonna need. No, I think that's it. Let's test it out. If you get an error, you get an error. Let's see. Let's check it out.

JASON: Let's see. Activated. All right. We've got our storage. Here's the storage. So, let's go to the network and let's test. And it fails.

PATO: Okay.

JASON: And it failed because of something that we did. We're not resolving these requests properly.

PATO: Mm‑hmm.

JASON: The FetchEvent for local host 8888, the object that was not a response was passed to respond with. So, one of these is not actually a response.

PATO: Oh. Okay. I think I remember why. So, with the response with, we need to pass everything from the ‑‑ from the return, right?

JASON: Mm‑hmm.

PATO: If I'm mistaken, could be wrong. Before the with async. Await ‑‑ no, let's see. Okay. Open a parenthesis.

JASON: Where?

PATO: Right there. Yes.

JASON: Right here?

PATO: Yes, sir. No, just, like, close ‑‑ remove that one. Okay. And we need to ‑‑ in line 23, exactly where you have the curser, you're going to open a closed parenthesis. So, basically, we need to trigger the thing inside to pass with. Open the parenthesis. I think that's the problem.

JASON: So, actually call the thing?

PATO: Yes. I think that was the issue.

JASON: Okay.

PATO: Let's test it out.

JASON: See if we can get it to ‑‑ okay. So, that installed the service worker. And if we look, look at that.

PATO: There you go.

JASON: There's our service worker.

PATO: So, that was the problem, right?

JASON: Now we can also see that 9.8 kilobytes was transferred. There are 940 kilobytes of resources because, again, we've got this big old image on here. Because each of these was cached, we didn't actually have to bring the thing in. So, our service worker brings in the icon, which we didn't cache. It brings it itself. And it brings in ‑‑ looks like it brings itself into in again over here. No, the manifest. Its own, like, local host self. Oh, so, it doesn't ‑‑ it doesn't cache index.html. Do I need to cache like slash instead of ‑‑

PATO: Interesting, yeah. Do that.

JASON: Okay. So, let's try that. Ooh, we can even test this. Let's do 2.0 and make sure that it does what we want. So, I'm gonna ‑‑

PATO: Hold on, Jason. Before you begin, I think just explaining to people what's gonna ‑‑ what's supposed to be happening, right?

JASON: Sure.

PATO: For cache, clearly has the image of Jason dash V 1.0. Now that we added the files we want to cache, we're caching out the image HTML and the name of my cache should be changed to 2.0. Just for everyone that is in the same channel. Okay. So, now let's test it out and break things up.

JASON: Okay. So, I'm reloading. And did I forget to save? No, here's 9 87. Now I've got ‑‑ did you see that? It went 2.0 and then it deleted 1.0. So, this is all great. So, now if I go out here and I refresh the page, everything except the manifest and the icon come from the service worker now. Which is great. Because that means that the vast majority of our app is now cached. If I go offline, does that mean it'll still load?

PATO: Let's test it out.

JASON: Okay. So, I'm gonna hit this offline button. I'm gonna go down here and I'm gonna reload the page.

PATO: There you go.

JASON: Offline support.

PATO: Now you're working offline.

JASON: So, this is a really, really powerful thing. And as you can see, this is a little bit Fink Ky. Before we do that, just a quick recap of what's happened here. So, we were able to define the assets required for our app to run. We were able to set up the service worker to create a cache and put this in it. Then whenever somebody fetches, whenever a request gets sent, that's why I'm saying this is a full proxy. That's why this is so terrifying because if somebody could get one of these on to your website and you didn't know about it, they could change every resource on your website to whatever they wanted, right? So, that's why you need such security around service workers. But we're able to go check if we have it cached. If so, we don't even bother making a request. We send it straight back from the service worker. You save all that bandwidth. You save the HTTP time.

PATO: Performance is going to be great.

JASON: Cleans up old caches and claim the current client with our service worker to make sure that it's actually running. So, this is a very, very basic way of getting this set up. But you can see how this could expand. I love this stuff. It's the sort of thing that when you have a need for this, this is so incredibly powerful, right? So, we are short on time, so, I want to make sure we can get to maybe more practical things. Because probably you're not gonna write your own service worker, right? That seems like maybe you might hit a use case where that's necessary, but probably you won't. So, where should somebody go if they want to get this configured?

PATO: Can you explain that? What you mean?

JASON: You mentioned Work Box earlier. If somebody's gonna get into production service workers, where would you recommend they go?

PATO: Okay. So, first of all, we need to define what Word Box is, right? I think that's important. So, why don't you type Word Box JS or service worker.

JASON: This one, right?

PATO: That one right there. So, Workbox is a super light open‑source library that is going to make your life easier with JavaScript service workers, right? As you can see, it was very easy to mix up with the service workers. I don't have everything memorized from the top of my head. It's very painful because you have to write everything by hand.

JASON: Mm‑hmm.

PATO: We developers, we like to be lazy and smart and do things easier. Some geniuses came up with Workbox. Essentially what it does is removes the boilerplate of writing the service worker and you focus on the things that matter the most, right? Like the caching strategies. So, Workbox is amazing. I want to say probably the majority of people who are building big applications are using Workbox. They're not writing their own service workers by scratch. But I think it's very important for us to show you how service workers work.

JASON: Right.

PATO: Without using Workbox because you need to understand the basics, right?

JASON: The way that I look at it is, you know, you can never learn a thing about service workers, use Workbox, and you'll probably be fine.

PATO: 100%, yes.

JASON: But when you hit that edge case, you hit that thing you're not quite sure why it's doing what it's doing, knowing what's happening with service workers under the hood will make you faster with finding the bug. If you can write React or Vue or JavaScript, you're okay. You learn the underlying JavaScript, you're going to be faster when you need to solve a problem in a different way or hit the edges of the framework. It's one of those optional but very helpful.

PATO: Exactly.

JASON: Okay. So, Workbox. And then I saw a question. What shampoo am I using for my beard? I don't use shampoo for my beard. It dries out the skin. I use what's called a beard balm from a company called Colton King that puts a little oil into it so my skin doesn't dry out.

PATO: And something else I wanted to talk about service workers is, for example, you have a super tiny website like the one that we just built ‑‑

JASON: Mm‑hmm.

PATO: I would say in my personal point of view, a bit of overhead to integrate Workbox.

JASON: Sure.

PATO: You know, you just learn how to do it. How to do a PWA by using a regular or normal service worker without using Workbox. It's good to know both if you can. If you don't want to learn how to build your service worker from scratch, that's 100% valid. If you're using React, for example, you can convert your React application into a PWA just by literally running one command, right? For example, if you're using Create React App. And Create React App uses Workbox. They don't think it's necessary for you to learn all the ups and downs from service worker. So, yeah, definitely ‑‑ that's definitely a good tip, Jason. So, now if you scroll down, the Workbox page. You can see how can it ‑‑ oh, scroll up. Right there. Why Workbox, right? Like I was telling you, Workbox already follows the best practices for the industry whenever you're working with JavaScript service workers. That way you don't make the mistakes that you can potentially make and try to debug a service worker. So, it's very helpful for caching strategies like pre‑caching, runtime caching. It is very easy to work with with a background sync API. Which is gonna save you time. So, definitely take a look to Workbox and, yeah, anything else that you want to add, Jason?

JASON: No, I think Workbox is great. The API on this is not super heavy. You can do, like, this is not a great example because it's, like, here, five new concepts. Here's one thing that I will say about service workers. Service workers are one of those things that it ‑‑ you may be looking at this right now going, why doesn't every website use this? And there is a reason. First and foremost, a lot of websites have too much content and they're not particularly useful if, you know, because there is a limit on how much you can cache. So, you shouldn't be trying to cache 8 gigabytes worth of stuff in people's browsers. If it's an informational website, a blog, something like that, it's not necessarily useful. And there is a huge foot gun with service workers. If you register them incorrectly, you can get caught in a weird loop where your website won't render and then people can't clear the service worker without getting into their DevTools. So, you want to make sure that you're really careful and doing a good job of testing your service workers before you completely hijack all the requests on the site. Because if you get it wrong, it can be so painful to clear this up. What I would recommend is if there is a happy path for whatever tool you use, if, you know, if you're using Gatsby, there's an option. I believe there is one built into Nuxt and a handful of other apps out there. I'd like this to be a PWA. They'll configure Workbox in a way that is pretty tested and not gonna get you in trouble. If you're gonna hand write one for yourself, test the bejeebus out of it. The last thing you want is to have to send an email to all of your customers and open up service workers and how to get back to their website. Ask me how I know.

PATO: Retweet. (Laughter)

JASON: So, it's definitely something that you just want to be aware of the power of this. Because it is absolutely a great power, great responsibility tool. I have loved them. I've made some really, really cool things and really powerful things with service workers. But, yeah, it is one of those things that if you go into this with a Cavalier attitude, you can get burned pretty bad. Just be careful and make sure you know the risks as you're deploying things like this to production. Pato, I think that is all the time we have today. So, where should I send people? I'm gonna send everybody to your Twitter, first and foremost. Any other links or resources that you want people to check out?

PATO: I posted the links already in the chat of Twitch.

JASON: Yes.

PATO: I don't have a problem doing it again.

JASON: You dropped this one here, intro to Progressive Web Apps and service workers. We'll make sure this is in the show notes. This one back here. Progressive Web Apps from web.dev. We'll make sure that shows up in the show notes as well. Anywhere else you want people to go find you or check out?

PATO: Oh, yeah. They can even check ‑‑ I just posted another link. It's a link to a repo that I have where I show people how to build a Progressive Web Application. And there's two branches. There's a master branch and a dynamic cache, right? So, the master branch, just to talk about that really quick. The master branch has, like, the basic setup that you need for your service worker. Then the dynamic one caches an actual API call.

JASON: Cool.

PATO: That is the difference. I wish we had time to get into that one today, but, you know, we can talk about service worker for, like, we will never be done with them.

JASON: It's a rabbit hole. It can do a lot. Okay. With that, we are out of time. So, this episode, like every episode was live captioned. We've had Jordan here with us from White Coat Captioning. That's available on the homepage of every episode of Learn With Jason. That is made possible through the support of our sponsors, Netlify, Fauna and Auth0, all kicking in to make this show more accessible to more people. While you are on the website checking things out, make sure you go take a peek at the schedule. We've got a whole bunch of great stuff coming up. We are later this week on Thursday, we're going to talk to Segun Adebayo, is going to talk to us about Chakra UI. I don't know what the fuss is all about. I'm excited to see how it works. We're going to talk about Svelte or Auth0, if you're not familiar, both are very cool. Michael Chan is going to come and teach us about attachment selectors. Gatsby WordPress themes. Distributed databases. A whole bunch of stuff I haven't put on the website yet. Stay tuned. Make sure you hit this add on Google Calendar.. Give a follow on Twitch. We go live every Tuesday and Thursday. All right, y'all. I think that's all the time we have. Pato, any parting words?

PATO: Thank you for your time. This was amazing. Hopefully people start learning about PWAs and applying the concepts into their web applications.

JASON: Absolutely. Thanks, y'all. We're going to go find somebody to raid. Pato, thanks to your time. We will see you next time.

Closed captioning and more are made possible by our sponsors: