skip to content

Service Worker Science Lab!

Service Workers are extremely powerful — in this episode, Jem Young and Jason will do Service Worker experiments to see what kind of fun we can cook up.

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, where we're going to learn something new in 90 minutes. Today we have Jem Young.

JEM: Thanks very much. I make no guarantees about learning anything in 90 minutes. He said that, not me.

JASON: I love it. Yeah. So before we get started, a couple of things we have live captioning. Remember that you can go to LWJ.dev/live we've got captioning being done by White Coat captioning and we have sponsors kicking in to make this more accessible. So thank you for that. So gem, I'm going to tell a story because I met you back in at Perf Matters a couple of years back. We both spoke there and it was such a fun time I remember just kind of laughing my ass off the whole time and I remember from there I discovered front end happy hour. And it's the kind of show that I feel like it's the show that I immediately was like oh, man, how do I do something that fun. So I actually thought about it quite a bit because I wanted that same kind of happy hour for me to form this show.

JEM: I appreciate it improvy style we were trying to go with. Ours is more amateur. So we don't actually know what we're doing. We still don't know what we're doing. So I'm glad we're still keeping the improvy vibe because that's what we going for. Not because we don't know what we're doing, but we don't. I appreciate that, and I do remember meeting you hear in the Bay Area for Perf matters and was like he's a cool dude. Now it's the future and I'm really glad you're doing this show.

JASON: It's the future. Here we are. It's arrived. So fronte end happy hour is a podcast where the format is brilliant because you've turned it into a great drinking game where there's a word if anybody says that word you have to take a drink. How is that going now that everybody is in quarantine? You're still doing them remotely, right?

JEM: I've actually been on paternity leave since January. I came back last month. I don't know if anybody out there has kids, let me tell you it's not a lot of fun going from a full-time job taking care of a baby back into a full-time job. That's not fair. It's been going really well. The team has good spirits and the nature of the work we're do, we're fortunate to be software engineers where we can work remotely where a lot of people can't.

JASON: Absolutely. So like I feel like I half introduced you. So for those of us who aren't familiar with your work, do you want to give a bit of a background about who you are, what you're doing, all those fun things?

JEM: Yeah. Like Jason said, thank you, I'm Jem Young I'm a senior software engineer at Netflix. I work on infrastructure for the growth team. Funny enough I don't do a lot of UI these days. Meanly what I do is the tedious back end stuff having sources talk to each other and thinking of ways to keep our infrastructure strong a couple of years ago which is, I don't know. It's a discussion we can have as we're coding about what it means to be a senior engineer and kind of the misconceptions of all we do is code all day, which is not true at all. But that's what I do for fun. What I do for work, my own joke, sorry. My wife and my three and a half month old son. I spend most of my time laughing at my own jokes because nobody gets it.

JEM: I whisper while he sleeps and I'm dad's a lot of fun. It's true. What I do for fun is probably the same thing everybody else does for fun these days which is try to keep off the quarantine 15, not working really well. The temptation to snack is so strong, Jason. It's so strong. Criticize a lot of Netflix. Been doing that. And recently I got into the great Canadian baking show. I don't know if you're familiar with this universe.

JASON: I'm familiar with the British one. Did the Canadian one -- I feel like I watched an American attempt at making a baking show and they added laser lights and intense music and drama and I was like no no, you're missing the entire point of the British baking show. Did the Canadian one keep we're all nice and going to take care of each other?

JEM: You know they did. You know Canadians represent for Canadians and Americans. Yeah.

JASON: I had hopes. I want to believe.

JEM: I've never seen the American one. I've heard stories that we also have attempted a baking show -- for those of you who don't know, and are buried under a rock, the Great British Baking Show is one of the most popular shows in Britain. It's actually one of the most popular shows in the world. And it's just a series of -- I want to say 12 contestants and they have three challenges issued by these master bakers. So every week there's amateur bakers, phenomenal works of pastry and things like that. It's a competition but it's not competitive. It's really wholesome and you feel good after watching it. So apparently what Jason is referring to is that there was supposed to be an American version of this. But because our natural American competitiveness -- I haven't seen it.

JASON: It's like American reality TV has a thing where we can't make a TV show -- the reality formula in America is where we need drama and undercutting and focus on all the bad things and the smack talk as opposed to let's see people who are really good at a thing building a thing and being nice to each other while they do it which is what makes the great baking show such a good show is these are people who have a lot of skill. They are pleasant. They're nice to each other. They help each other and they're all trying to make a thing. It's a competition they obviously want to win, but it's never like I want to win at all costs. It's like I would like to have a great time and hopefully I win. Which I feel like is something we've lost sight of in reality television.

Yeah. You summed it up precisely. I don't know. Sometimes I start watching American television, and life isn't a zero sum game where one has to win and the other half has to lose. We can all win that's what I love. It's the idea that you push yourself as hard as you can and by the time you get to the end you know these people are just better than me. I've worked as hard as I can and they're just better than me and that's okay I've found out what my strengths are and how far I can go. You see the mental process working. Now I'm getting too deep into it.

JASON: One of the things I think is most telling about that show is they do a -- after they air the final episode, the end is a montage contestants continuing to be friends. We're going to talk about this all day. Chris, thank you for the sub. Appreciate it. Before we talk code, we have one request from the chat. Is your cat within arm's reach?

JEM: No. He knows. Like he's pretty useless most of the time. But his one super power is knowing when I'm going to go pick him up. He'll be sleeping and he'll be like -- Jem's coming. I have no chance. I might be able to catch my baby, maybe. But I guarantee nothing.

JASON: There was a good discussion of your cat's laser eyes and I think everybody wants a demonstration.

JEM: That was my wife. She put that all together.

JASON: That's amazing.

JEM: The outfit so you know, that was real. That was not photoshopped. I own that outfit.

JASON: Let's talk a little bit of code. Let's make sure we don't completely go off the rails here.

JEM: Do we have to talking about baking.

JASON: I really could. Let's talk about we're going to do some service worker stuff today. What is the big idea behind service workers?

JEM: You tell me, Jason. You tell me. So there's a few basic types of -- actually, no. Let's step way back. Javascript is single threaded, everybody knows that. That means if you do something that takes a long operation, everything is going to freeze because everything is running on this one single thread on the processor. Years ago somebody, I forget who, we'll say the Internet gods. The Internet gods invented the idea of a worker and the worker is a separate thread you can spin off. You can't do any sort of creative rendering in there. I need to preface everything. You probably could, you probably won't you probably should because we're engineers. But generally has it's for running long computational processes. There's such thing add an audio worker but later a few years ago someone the Internet gods invented the idea of a service worker. It has the unique ability to intercept network requests. Also it has several unique abilities. It can intercept network requests. It can be used to cache things offline. It can be used to do background push notifications so if you've ever gotten a notification and your browser is closed, that is a service worker. It's an on-demand worker. It only exists when it's running and it's persistent. It's always in your browser unless someone uninstalls it for you.

And that exactly like always present in your browser, is one of the things that make service workers so intimidating . I've seen there are huge threads dedicated to how do I uninstall a service worker. When I used to work at Gatsby for a while we would make sites offline for a default. So that when you shipped your site it was offline compatible but we had so many problems we actually had to reverse that and publish a plugin for Gatsby that would uninstall the service worker. So you have hit this? Do you have any like any personal scars? Because I have personal scars. I borked my whole site once?

JEM: Yes. I have also broken my site. Because when you have something -- I'll just say like the easy route to doing this is you have a worker that runs on a separate threat, it's persistent. So you install it one. You can cache your entire site. Which is what most new people do. They are like I'm going to make it also works offline. Good idea. The problem is they don't install the mechanisms to update that service worker once they get going. So what happens is you load a site, it caches the entire site. So Jason Lengstorf is awesome.com. Cool. It's all cached, you push an update. No one can get it because you didn't put on an mechanism to manually cache. You're refreshing the page and unless someone is an engineer they're never going to be able to uninstall the service worker.

JASON: Even as an engineer, I feel that was something I learned literally months after I had broken my first service worker was how to delete a service worker manually. I was opening incognito windows. My work flow was terrible.

JEM: I love you in incognito because it's so sneaky and you're like why is this not working and it could be dozens of things. But what it's there is sitting there and there is nothing you can do about it. Fortunately a lot of dev tools have come a long way. By we, I underestimate the effective tooling we have in this environment. People have done better work now because the tooling is there when it's installing, how to kill it, how to refresh it, all these sort of things we didn't have so you're guessing. And I was deep into the archives of the Internet because service worker was so new nobody knew what they were doing yet. They are dangerous if you let them be out of hand.

JASON: For sure we've got a couple of questions in the chat. So it's like an Android app for your browser but without an app store. Sort of, like you can use it for that. Like you can do the web apps. It's a portion of that. Like offline support is part of making a full like offline first progressive web app. You also have to use stuff that has nothing to do with service workers like a manifest and things like that. The other one is sort of like an orchestrator router. It can be. Like you can use it as a proxy, you can use it as a -- you can use it as a lot. -- it might make more sense to just start playing with this, right?

JEM: Yeah, yeah.

JASON: So let's do this. Let's switch over into code mode.

JEM: We're going to code? Crap. I thought we were going to talk about baking.

JASON: Just as a reminder this is the lwj.dev/live if you want to look at the captions. Remember again thank you again to the sponsors. And with that, this is also, this is Jem on Twitter you should follow if you weren't aware of what we were talking about with the laser eyes cat, that's what we were talking about. This is amazing, so good.
Also, I just now for the first time realized that this is a Ramen pair of pants. When you said that you had not photoshopped the outfit I was like I don't remember the outfit being ridiculous I was so distracted by the laser Kathy didn't notice the Ramen packet

JEM: And the Ramen noodle shirt. This is my Halloween costume two years running. Last year I was filming so I missed Halloween. The year before I feel like I was out of the country so I've had this Halloween outfit for two years and I've never been able to show it. I've got the pants, I've got the top and I was going to walk to the office and unzip the Ramen noodle and it was going to be a packet underneath. I had a whole thing. It was going to be sweet.

JASON: So what we've done is set up a VS code live share instance and we are going to just build out a little site, I think, right?

JEM: Yeah. Let's start there.

JASON: All I've done thus far is created an index.html but it's empty.

JEM: That works. We would need a few tools but I feel comfortable doing them. But we'll get there when we get there. I'm a slow typist so I'll get you to do this part because I'm lazy. Let's create an HTML page. Perfect. To make something from scratch you have to first invent the universe. I think I'm going to jump in here.

JEM: It's going to bother me, but. . . I'm trying to line it up.

JASON: What is it doing?

JEM: Okay, I think we're good now. All right. Let's go ahead, if you would, let's make a worker file. Let's make a worker.JS.

JASON: This is something that's worth calling out. Two things. One, doesn't matter what it's named. And two, does it matter where it is?

JEM: It doesn't matter what it's named it does matter where it is. I want to build a really quick example to show people why we need workers. Because it's one of those things that's not apparently clear when you're first starting out. At least for me it wasn't. Javascript works all works in this one thread let's build out a thing that says why we need a separate worker. Actually I'm going to come up here and make a button. Nothing special. So if you would, would you fire off a quick server and we can load this up?

JASON: Let's do it. I think we can even share a terminal session. I was going to use python server but this is much fancier.

JASON: This is nice and fast. Pretty painless. Let me get this open in the right browser. If we open up the console and I close that.

JEM: We are Javascript wizards.

JASON: We've done it. I feel like I'm ready to take my whiteboard interview.

JEM: I feel like our valuation could be somewhere in the billions? Maybe trillions for this one.

So we have this basic HTML the button, we click it, it says console we're all familiar. Now let us example the pit falls why single threading is not necessarily an ideal case. If anybody is like what that's not going to work, remember while it's running it will never get to the line below.
I don't want to give it ten zeros. This is log rhythmic, it might take 10 seconds now. But if you're refreshing the page and clicking the button, nothing is going to show up because that wild loop is still running

JASON: And they queued too. So like, 1, 2, 3, and it queues and I get three clicks at the end. This is when you're trying to talk about first input delay. The interactivity of the page is blocked by Javascript. We did too much work in our Javascript and that prevents the person actually loading the page from doing things on it. And you were able to do that with five lines of Javascript. Just keep it in mind, it is not hard to make an app slow.

JEM: Exactly. It's trivial, really. This is a very straightforward example. Most of the time synchronous calls are blocked we don't know about. JSON.parse is a synchronous action. When it gets that giant pay load and it's parsing it, your UI is locked. A lot of people don't know that. The idea stands.
All right. So this is bad. This could be any use case. It could be building a graph, processing audio, something blocking your UI. Without the console a user doesn't know what's going on. Let's offload this work into a worker. So actually I'll let you do it. Copy the work into worker.js

JASON: There's my work in the worker.

JEM: Copy the console log too. And then back in index.html, we can delete that out.

JASON: So now if we come out here, obviously we're not doing the work. Like it never happened.

JEM: Great point. We need to tell the dom we've got a regular web worker to load up and do some work on that. A const worker equals new worker and you can say worker.js. So now if we try our example again, we should be able to click the button while the calculation is running in the background.

JASON: Oh, that is beautiful. Look at it. So that's powerful stuff. Because what we just did was almost nothing, in terms of work. Like, the effort for us to move that off to a worker was minimal. But the impact was huge.

JEM: Yeah, well-put. Exactly. I just love this example because it shows, hey, here's what being a single-threaded environment does to you. But here's how we can mitigate that sort of thing. Now some people are -- sorry. You looked like you were about to go on a good point.

JASON: There was just a question about whether this was a normal worker and not a service worker. So this is what you would call a web worker, if you were looking for the spec, right?

JEM: Yes, this is a normal vanilla worker, web worker. There are many different -- there are several different types. So right now if you've never seen this before, seen an example like this, you're like what can I offload to my worker now that I can just make it faster. Can the reason why we don't upload everything to the worker is because we communicate with the worker using message passing back and forth. That generally means we have to serialize the message, the worker gets it, unserialize it okay they want us to do this? Okay. We pass that back to the main thread or the UI thread if you will. That's really expensive. Why which is why we don't see web workers passing data back and forth on all our modern web workers. Jacky, it's about to get noisy. Sorry. He just gifted out 10 subscriptions so we're going to get 10 new to everyone who just got your sub, remember, you are perfectly capable of burying us in the boop emoji. So make sure you take full advantage of the boop. Don't forget to drop those boops.

Are we done? Jacky, thank you so much. I really appreciate it. That is wonderful. I think we're almost done here.

JEM: I don't know a lot about the Twitch universe, but I hear subscriptions is a nice thing to do.

JASON: You support the streamer. You let other people who are watching take part in the emote fun because these emotes are only available if you're a subscriber. So it tends to be a fun way to spread the love around in the community which I have always pretty much appreciated.

JEM: Way to go, Jacky.

JASON: Now we can't see what we're working on because we're covered in boops.

JEM: Nobody is here to see us code. They're here for our baking commentary. So as I was saying about pies, let me list the favorite.

JASON: Okay. We're in full chaos mode now. This is good. This is wonderful.

JEM: I feel like my grandma when I set up Netflix for her. She's like what's happening? That's what I feel like now.

JASON: Thank you all so much for playing along. This is super fun. Jacky, thank you again.
We were talking about workers. So we've got a standard web work. And you were saying that the reason we don't just offload everything is because communication between the main thread and worker threads is expensive

JEM: Exactly. There are working in a single-coded environment there are more efficient ways to queue up work. One of the ways we do that is using request animation frame which is going to be called roughly every 16 or so mill seconds as a way of doing some work so when you're done, you can move on you can do work in chunks. I would say 99% of people don't do massive amounts of single threaded work we've gotten conditioned not to do it anymore. But there are cases for video or audio or like a real-time anything. You use a web worker and they're good to know. Oh, nice. Random jobs for concepts and you'll look them up?

JASON: Yeah. Got to have those showdowns.

JEM: Did you get baking shows yet?

JASON: No. There we go. We'll put the Wikipedia page. We'll be platform agnostic.

JEM: Don't forget that great Canadian bake off as well. It's so delightful, if you get to see it.

JASON: I love it. So this is the same -- this is actually the same cinematic universe. This is the same production company?

JEM: Yes. This is an aside, but have you happened to see the show Schitt's Creek?

JASON: Yeah.

JEM: You know the main character David, he is one of the hosts.

JASON: We're going to watch this today. This is the rest of my Memorial Day. I'm going to binge through the whole show.

JEM: He goes around eating everybody's food. Oh, is this extra? Don't mind if I do. It's hilarious because you're like that's what I would do if we were on a baking show. Anyway. Back to code.

JASON: We've got a worker. A worker is probably not the first tool you should reach or but there are good reasons why you would. Service workers are a specialized kind of worker. And so if we are going to kind of play here, how would you want to go about that? Like what should we do first?

JEM: Let's create another file. We can make a source worker in-line but I generally find it cleaner to make a separate file. Let's call it sw.js. So now just like our first example we need to find it to say there's a service worker let's load it up. I'm going grab this. I'm going to say navigator.service worker and the first thing we need to do is register our service worker. Because it's best to think of a service worker as a web worker but it's also an event-driven proxy. Which I tend not to use that definition a lot because it's just throwing a bunch of words at you. But essentially it's a worker that can listen for certain events. It will spin up in activation of those events and spin back down.

JASON: I was going to say like I like the definition of a proxy, because like a proxy, if you think about like what you're doing with a service worker is you're adding a step in between what somebody asked for and what they get. You're basically it's kind of like if you -- if you go to -- if you ordered a delivery, if you are at the restaurant and you watch somebody cook your food, they're going to give it to you directly but if you order delivery the driver is going to take that food for you and if you're using something like postmates they might add some paper silverware, they'll get some extra sauces for you and stuff that maybe wouldn't happen otherwise. Or if you've got an evil delivery driver, they could swap your food out and bring you the wrong thing. That's sort of what you're able to do with a service worker is say oh, you asked for this page. Here's what I'm going to give you. And it may or may not be the thing you asked for.

JEM: Yeah, that's a great way of putting it. That's exactly right. That's the hidden danger of the service worker it could be doing all these things in the background and you'll never even know it was installed.

JASON: The chat is saying the takeaway is to not register an evil service worker. You're correct.

JEM: Only good stuff. I love service workers because with Javascripts and just with Javascript and the dom we're creating UIs. With a service worker we can control the network as well. At some point you're building a web page we can do all sorts of fun stuff. But let's get the service worker registered and then we'll talk more about the things we're going to break. Which is many, many things. So I've got navigator which is just window.navigator.service worker, service worker is this global scoped object. So I'm going to say register and I'm going to call /sw.js. And that's all it takes right now to register our service worker. A lot of people -- yeah.

JASON: Save this. Like this is theoretically functional, right? Where would I want to go if I want to see my service worker is working. It shouldn't show anything once we initially hook it up.

JEM: Yeah. Right there in application. I saw your mouse over it but I appreciate you giving me the ball for this one. And you click on service worker. This is your Chrome dev console under application service worker and what do you know? It says it's up and running.

JASON: So we can see here's our service worker. We can update it, unregister it. We can choose to bypass it. We can simulate being offline. These tools are -- if you're going start playing with service workers, remember where this is, because this is your lifeline. When you inevitably break it, if you don't know where this tab is, you're going to have to buy a new computer to be able to do your next round of the service worker. This is the left expensive approach.

JEM: Or switch browsers which I had to do before. When I didn't know what service workers were I would switch to Firefox or Safari.

JASON: I've also done that.

JEM: Don't judge us until you've been there.

JASON: The chat is not even paying attention. They're debating whether or not cookies are a sandwich. Two cookies on top of each other is a sand wish.

JEM: Something would have to be in the middle for it to be a sandwich though.

JASON: A third cookie.

JEM: Would you call three slices of stacked bread a sandwich?

JASON: That's a club sandwich. It's not the sandwich I would want. But if you hold most of the ingredients that's what you're getting. I have a unified theory of food. I think that everything breaks down into one of three categories. Everything is either a soup, a salad or a sandwich. Not all of them are soup, salad, or sandwiches that you want to eat but they do fit into that general definition. You're so upset right now.

JEM: No, no.

I feel like we could debate this one for a while. But I have no concrete examples right now, so yes. I'll agree with you. Because I don't have the wherewithal to debate this one.

JASON: I've had like -- just kind of like long-running shit-talking battle with Sarah Drasner about sandwiches because she is hoity-toity and believes sandwiches need to have rules and I believe everything can be a sandwich so I might this site to troll her. I think this was my finest work. It was also a really good 11 in -- Sarah is my manager. So when you troll your manager, you kind of have to know how your manager works so that you don't get yourself accidentally put on a performance improvement plan or those sorts of things. So I've made sure to hardware accelerate that animation because I knew as soon as she saw that she wasn't going to look at the content, she was going to code review it.

JEM: Sarah is super smart. Wicked smart as they say in Boston. Didn't she make a site called a is it a sandwich?

JASON: That's how it came about. She made is this a sandwich and it's a completely incorrect assessment of what a sandwich is. And later we were arguing about what counts as a sandwich and she tried to submit this as evidence. And I was like you can't use your own website to support your argument. So I built this one to support my argument.

JEM: I like your arguments and your battles here. It's kind of like, you know, just go on Wikipedia and make your own page. Yeah, see it's on Wikipedia.

JASON: Exactly. It's on the Internet. It has to be true. All right. We should probably like actually write a service worker on this.

JEM: Did we get to code?

JASON: We wrote some code.

JEM: Yeah, that's good enough. Everybody in chat you got it, right? So what were we saying about sandwiches? The service worker is up and running. There's nothing in sw.js so let's put something in there. Normally I put like a console log like hello world or something like that. But as you demonstrated with the Chrome dev tools you can see it's running. Throw it in there. This is good code.

JASON: There we go. It's registered.

JEM: Funny enough, go to your application tab. We see that the service worker we installed first, which we can call it V1. They don't actually have versions that you can see. But we'll call it V1. That was just an empty file when you made V2 which said console service worker. The original service worker is still listening for events. Remember what we said earlier about it being a proxy? So if you have any event in Javascript, it has to be a listener for it to do anything. That service worker V1 is the listener and right now it's controlling the entire scope. Any requests we're trying to do are not going to hit our new service worker because we have to tell the new service worker and the old service worker like hey we've got a new worker coming in, stop what you're doing and let the other one take over. This is, I want to shoot out top tips. J & J's tops tips. Make sure you use this case. Don't forget the original one hasn't taken over yet. You can force it to work using the update and things like that or you can stop and skip writing all these things. But again if you're a user, you're not going to know about these things.

JASON: Right.

JEM: Actually while you're in there. A fun tip. Scroll down on the left panel. Actually, yeah. I want to show people how many service workers are actually running in their browser right now.

JASON: I think it's down here. Service workers from other origins?

JEM: Yes. Give that a scroll. Look how many service workers are running just from casual browsing of the Internet. Nobody even knows they're working because if the service worker is doing its job correctly, you'll never know it's installed and doing things in the background.

JASON: That's really the whole goal, right? You want stuff to just like function. And so on code sandbox I don't know what they're doing in the background, but presumably they're doing things that make my experience more stable, less laggy. They're trying to make things feel snappy. And that's great. And I haven't noticed that when I go to code sandbox that I need to reload the page to get things to work. Not unless I've broken the code. So that's a great use of a service worker. They've improved my experience completely transparently. I have no visibility or awareness that they've done this. They've just kind of made my life a little bit easier.

JEM: Yeah. Exactly. And well-put. The case for service workers. If you do things correctly people won't know you've done anything at all. That should be the idea. It should help the user experience but not degrade it or give them a frustrating experience which is trivial to do. So let's dig into the service worker a bit. Let's do some code. Let's make it do something other than just print a log. What do I want to do today? You know what I want to do? I've got to tell you, I've got to confess something to you Jason.

JASON: Please do.

JEM: Someone the other day sent me a really hateful meme about myself. They said it was just a picture of me and it said Jem was just an okay engineer. And that hurt. That's not true at all. I'm a terrible engineer. I'm the worst engineer on the team. I break stuff all the time, like constantly. I don't know how Netflix is up and running because I've been working there for like four years. Fortunately with a whole team of people their job is to keep the server up fighting me the entire way. Because I'm just an okay engineer according to some random Internet commentary, I do break stuff. I break a lot of stuff. So what I want to do is, I want to build a page that tells the user that hey, either your Internet is down or the service is down, which happens fairly frequently. I want to build an offline status page. And I know what you're thinking. If my Internet is out or the server is out, how is the status page going to show up? Normally it will be a blank or empty screen. But with the service worker we can create a page that will show up if the Internet is out or you can't connect to the network or things like that.

JASON: This is the power. You get this offline button so I don't actually have to go offline to see what that looks like.

JEM: Exactly. Shout-out to Chrome dev tools. They're rocking out there. We can build a service worker. I'm going to build out some of the scaffolding that I usually start most things. Because the service worker is event-driven we want all of this for events. I'm going to say self-.oninstall. You can do this @ event listener. Thanks auto-complete.

JEM: I don't even know where that's from.

JASON: Who knows?

JEM: Whatever. Equal to some function and like events. . . That's the install event. And where most of the work is going to happen is the fetch event. All right.
So right now our service worker is only listening to two events. The install event, that's after the service worker gets installed, downloaded, and it starts getting installed. So it's like okay, I'm about to boot up. What should I do? We'll fill it out in a second. The second one is the fetch. All network requests once the service worker is running will flow through this event example. Right now since it's empty it's not going to do anything. It's going to transparently see everything through. We can grab the request and do all sorts of fun stuff with them. That's the two main parts we're going to work with today. Actually, so before I get to the install, I'm going to add in some boilerplate here. The first thing I'm going to add in is -- no, no. I'll go back to boilerplate. But I'm going to say this. Eventually we're sorting files in a cache. I'll jump back to this. Foo. I'm kidding. Do not name your variables foo. Test. Even better.

JASON: At least it communicates something in human language.

JEM: You mean foo doesn't tell you all my events and purposes and hopes and dreams in a variable? Weird. I'm going to give you an empty array for now. Am I supposed to do something?

JASON: They want us to call it boop.

JEM: Just for you I'm going to call it boop. Even more useful. The service worker downloaded and it's just waiting right now. What we want to do first is we want -- when the service worker loads up, we want to pull in this offline file so it's going to be something like offline.html. We want to save it to the web cache and once that's done, we want to say hey, the service worker is ready to go. But we don't want the service worker to take over any work until this work is done. So kind of pre-work. So we can say exactly that. We'll say event, wait until and that's just a function that we're going to pass something. So what do we want to do next? We want to open the web cache. Do you know about web cache? Of course you do. You're Jason Lengstorf you know about web cache.

JASON: So it's been a long time since I've looked at it, so remind me and for anybody who's not familiar, let's talk through it. Let's pretend like I don't, because honestly I would have to Google it right now because I can't remember how it works at all.

JEM: I look up most of this stuff and if anybody is saying wow, this is a lot of weird lexicon and different language that I'm used to working in Javascript, don't feel bad. Once you get kind of boilerplate for a service worker, you don't have to touch it too much. You're generally going to use these events to put some other function in and we're going to call that function good work. So when you're first looking at stuff it's really intimidating because it's things you've never seen before. Have no fear, you do this once or twice or look stuff up like I do, I look stuff up all the time especially CSS.

JASON: You're a senior engineer, I'm a senior engineer. And as I've progressed in my career, I don't feel like I've gotten more things in my head. I feel like I've learned more of the right way to search for answers. Like I don't know more stuff, I know where to look to find the stuff. And I feel like that's something that maybe doesn't get communicated clearly about becoming senior. It's not about memorizing the whole Internet. It's about learning where the connections are so you know where to look.

JEM: Well put. And maybe if we actually finish this thing we could have a deeper discussion about it. It's something that's worth talking about.

JASON: I agree.

JEM: Some people will say Jason Lengstorf you must be a master coder who knows everything. The runtime of every algorithm ever, but that's probably not true. We look stuff up. Depend on stack over flow and people's blogs. Where it matters you'll get to a point where you get to some nuanced problem that you can't look up, something specific to your case. That's one of the biggest differences between a senior engineer and a junior engineer what do you do when you can't look up stuff anymore and you have to figure it out. Anyway.

JASON: That's like -- now I'm going to have to come on your show and we're going to talk about this. That would be so good.

JEM: I would love to.

JASON: All right. You heard it here first. It's happening.

JEM: Happy hours are filmed at night with many, many beverages.

JASON: I'm so into it. I have this whole liquor cabinet that I've been not using at all because -- I usually don't drink alone. I'm a very social drinker so having a excuse to get in there would be great.

JEM: We don't need an excuse. We have a podcast to do it for us. We were talking about web cache. Web cache is a persistent mechanism. If you're thinking I already have local storage, I have index DB, I have cookies. There are lots of ways to sort things on a browser. Web cache is just one of them. Probably one of the newer ways of doing it. It's more persistent than -- I shouldn't say more persistent. I'll say it's more persistent than local storage for a bit. Don't @ me on Twitter. But we're going to use the web cache to store something. In this case we're going to store an actual file that we can access it later, and that's probably one of the big differences. You can take a file and you don't have to parse and code it and stuff like that. The way I'm going to do is open the cache. I'm going to say caches open and I'm going say that cache name I said earlier. What will get you on this is all of this is asynchronous. So because this is asynchronous and we're not using asynch anything, we could, but I'm going to say wait for it to open, I'm going to say then, function. So now my cache is open. Now that I have I'm going to grab it via the cache and I'm going to -- I'm going to return the cache.

JASON: Okay.

JEM: I'm going to say cache.addall and I'm going to give it this files. So what we're doing there is, the service worker comes in, it's getting installed. We say hey don't tell the browser you're ready yet until you open the cache, you get the cache and then you add all the files that you want into this cache. So we're just making sure that immediately the service worker is able to handle things offline. I'm going to give it I don't know. Offline. Perfect.

JASON: Just continuing with that --

JEM: I'm going to make that a fancy -- I'm terrible at styling things. That is accurate. That is perfect.
That's our install event. We will come back to this. I'm going to leave this line open for later. We'll come back to this and solve it. But for now, you know when your service worker is ready it has already loaded up the files it needs and it's ready to go. So now let's jump into the fetch events. So right now the service worker isn't doing anything. It's installing and hanging out. We want to intercept all the fetch events going out, determine if we're offline or not, and then if we're offline we want to serve the offline.html from the cache. First thing let's do, let's grab the request off the event. So now we have the actual requests. Funny thing a lot of people don't know, request is a type of object in Javascript. A lot of people don't know that.

JASON: I did not know that.

JEM: But what we get from this is not just some random variable. The fact that it's an object means we can grab the method off it. Just for this example I can say request.method equals get -- so we're being safe here. We only want to turn a service status for get requests. That can get tricky. There are better ways of handling this. We're specifically saying just for get requests there's nothing at stake. I call this out specifically because developers will forget it and hey I just spent 30 minutes writing up this email or something and I hit send and it just lost all my data. If you're offline it will say hey do you want to resend this data. It's important to remember that the user. Ultimately we're trying to make this better for the user.
So only for get requests, what do we want to do then? Hm. So remember, these are event listeners. So everything eventually has to respond with the event listeners. I'm going to say event, respond with. That means at some point once this event listener it's going to say something. It's either going to say hey I made your network request and came back you're all good or I'm going to deny you getting anything. We can do whatever at this point. But that's what respond with does. This is a good time to take a break and talk about my favorite cake. The Swedish princess cake. It is a round marzipan covered dome. It's green, it's got a cherry on top sometimes and raspberry frosting or raspberry jam frosting, cake, frosting and it's covered in whip cream and you put a marzipan dome around it.

JASON: Have you ever actually eaten would have of those.

JEM: It turns out Safeway sells princess cakes.

JASON: Is it actually good? It seems like it's too much.

JEM: It's not great but it's better than making my own.

JASON: They're beautiful. Like I saw the episode of The great British baking show and they made those, the one they showed off, that thing was gorgeous. It was an aspirational cake.

JEM: Isn't it where Nailed It came from? Where people see pictures of things on Instagram and that should be achievable and it turns out horribly?

JASON: I just had one of these moments. I have a friend, Leslie she was on the show a little bit ago and she's a designer but she also used to be a professional baker. So for my partner's birthday last year, she made this amazing -- it's like a really simple American-style yellow butter cake. And then she made like a chocolate frosting. And it was just this beautiful, fluffy cake, just like perfectly executed. And I was like we're in quarantine this year, my partner's birthday was last week. She loved that cake, it's a plain butter cake maybe if I get the recipe I can do this. So she sent me her recipe and I tried my little heart out, but it was not great. Let me see if I can find -- I'm going to find the photo of this. The reason I bring this up is because I did the Nailed It thing because of how poorly my cake came out.

JEM: I like that people in chat are calling a cake a sugar sandwich.

JASON: That's accurate. But this is so this is what Leslie made it was this gorgeous cake. She doesn't like carrot cake so this is a yellow cake decorated with carrots. And this is my sad little flat cake that just went everything that could have gone wrong, went wrong. We ended up -- here's how bad this cake was. We ended up throwing it away.

JEM: Oh, no.

JASON: I don't throw away food, especially junk food. Like I will eat it even if it's mediocre. This was bad. I had was bad.

JEM: Did you use salt instead of sugar or something?

JASON: I swear to God I followed the recipe but it didn't inflate, it was dense and kind of like -- I don't know. I overheated the chocolate so the chocolate got all weird and grainy. It was all bad. The whole thing was bad. Anyways.

JEM: We can get back to coding now.

JASON: Why did I bring up my shame cake? I shouldn't have done that. Now I'm sad.

JEM: Didn't you make a cast iron pizza?

JASON: I did. That, on the other hand, was awesome. I have to redeem myself.

JEM: I got the inspiration from you. I saw that I've been thinking about that and I also made a cast iron pizza -- ooh.

JASON: This recipe -- it's Adam Ragusea cast iron pizza. This recipe is very straightforward. And it's not super hard to make and it is delightful. I would highly recommend giving that one a try. I'll put this in the show notes. Yes, that cast iron pizza though, the truth. You should do it.

JEM: I recommend it. It wasn't that hard. It's actually fun. What else are we doing? You've got nothing else going on.

JASON: Exactly.

JEM: All right. Back to our service worker.

JASON: I swear to God we're going to write one complete service worker during this episode.

JEM: If we're ever somehow like -- if I'm applying to work for a company that you work for or vice versa, they're going watch this episode and be like those two are never allowed to work together.

JASON: Opposite ends.

JEM: 24 lines of code.

JASON: All right.

JEM: So, at this point we're saying okay. To get requests that we intercepted we're going to respond with something. So what we want to do is we actually want to respond with a request. So I'm going to say fetch and the request. So all that's going to do is respond with the results from originally the request.

JASON: And so if we're thinking about this in terms of what the network is actually doing. So when I type a URL into the browser, we're sending off to a server, we're saying hey browser I would get, use the get request. I would like to get this resource, which is a file name. And the server would, like, interpret that request, go retrieve that file, and send it back to the browser which will display it. So what we're doing here is kind of mimicking that behavior where we're saying oh, if it's a get request, we're going to send whatever the result of that request is. So right now it's kind of like, the browser will do it for us. So it's not super meaningful that we're doing just this. But this is where service workers start to get powerful. So what do you want to do next?

JEM: Well, that was well-put. And essentially, yes. You're 100% correct. Not essentially, you are correct. We're doing superfluous work. We're not actually doing anything. The power is going to come in here. We're going to say catch and give it a function. I'm going to leave the error off for now. So this means that if there's an error getting this request, so the Internet is down or the server is down, we want to handle it somehow. And this is where all the magic comes in. So we want to return -- ultimately what we're trying to do is we want to return the offline page. So to do that the first thing you have to do is open the cache. Go back to our caches. And then we're going to say that's a then and we'll give it another function and we have the cache. So this is just like above. And in an ideal case we would off load this to a function that's like get me something from the cache. Like we were saying earlier I know this is confusing but if we took opening the cache and offload it to the function you would have this boilerplate built out and you would be familiar with how caches work.

JASON: I can do a save and it will autoformat. This is going to go chaos. Did that make it worse?

JEM: No, no. It's just easier to read especially if you're writing -- you start chaining things or you do a lot of methods, I find it easier, some people don't. To each their own. I prefer readability over quick one-liners.

JASON: I agree.

JEM: So in the cache we want to look up the closest thing -- we want to look at the file we want. We're going to say cache.match and we'll say, what did we call it? Offline.html. And that's it. So what we did was we said hey, make the request normal. It should just be a transparent proxy. But if there's any sort of error at all, open the cache, get our offline.html page and return that page.

JASON: Do we need to return this cache.match.

JEM: Oh, yeah. This is why I'm a terrible engineer. Maybe in another 10 years I'll actually earn my senior title.

JASON: Okay. So if we save this, then this should be working, right?

JEM: Yeah. It will work for now. We just need to add one more line and we'll be totally complete. Funny enough, I sent my wife this pizza recipe and she's like did you send me a square space ad? I'm like no.

JASON: Something interesting here we just changed our service worker. Watch what happens here when I refresh the page. See how it just did all that? And now we've got another one in here that is wait to go activate. So I can like click this button to fix it so now we're running the most recent version. Which is very cool. So then if I go to offline and I refresh the page, I'm just going to click this. Ooh, didn't work. Okay. All right. So then what happens?

JEM: We did something wrong.

JASON: Did we respond with -- did our offline ever actually register, do you think? Here's our offline html. Maybe it needed to load once before I did this. Let's go offline.

JEM: Why would it load. . .

JASON: If we go to offline html. So the page works. Oh. Hold on. Is it doing -- what was that? Why is it not doing the dot html?

JEM: That's weird.

JASON: I think it's the serve module being awkward. Let's try instead of serve, let's use npx http server which I think does less helpful stuff. So it should be on 8080. So now that's not helping anymore. If we go to the home page, here is our service worker. Let's go offline. Okay. So it was the serve module was dropping our dot html. If we get rid of the extra help from the server, it does what we expect.
So now we're offline. And when we try to go to our home page, it shows us our offline html. If I go back online there's our button, it works

JEM: Exactly. And granted this was a very simple example and it's not an elegant offline page. If I was a user and it says you're offline, okay, cool. But it's a great place to put in your Twitter links or telling the user here's what happens we think you're offline or the server is offline to help them out. This is for the user, after all. But there's one last step I want to throw in there. It's because we had to go into our Chrome dev tools to manually update the service worker to say hey I want you to take over from the previous one. We can fix this. I'm going to hack this out. Technically we should do it somewhere else. I'll do it in here. Because I'm a gentleman. No. I'll do it out here.

JASON: I need like a monocle for that particular moment, like a gentleman.

JEM: That's how I code all the time. Good variable naming.

JASON: Indeed.

JEM: But we can skip that step. We can say self, which is self, which is the worker itself. We can say skip waiting. And that way every time we add a new service worker, it's automatically going to take over from the previous one.

JASON: And when I reload, it's immediately to 1115. At what point would you not want to skip waiting.

JEM: One, generally don't do this. But you want the skip waiting as part of the install step of when the install step is actually done or the heavy lifting that you're doing. So for this example, we're just getting a file locally offline to html and the files, and we're just loading them and it's pretty fast. But if you had actual libraries you want to load up or if you want to do some sort of processing of data or if you had generally if it's an offline page, you're probably going to load up react and a bunch of other things you want to serve out to the client. At that point you want to wait for the requests to go out and then load up the files in the cache and then you want to skip waiting. Because you don't want it to come in early. --

JASON: So the reasoning for that is when you hit this page, the first time that someone loads it, it's going to actually block doing anything until it completes all that work. Is that right?

JEM: It won't block because it's in a worker but the service worker won't work. So if you have any sort of like on-demand functionality you need it to happen right off the bat, it won't work until that service worker is done installing.

JASON: If we had a proxy in place, it literally wouldn't respond until it finished doing that work. So it would have to download all that stuff first so our page would be kind of unresponsive on the first use. So that would be why you -- so when you skip waiting, then what's happening is I've got the old service worker and I load the page and then in the background it does all that work. And then the next time I reload it's already got that work finished so it's like there's no delay?

JEM: Exactly.

JASON: Okay.

JASON: And we're just shortcutting all of that with this self skip waiting because we know opening the cache or unloading the cache is going to be fairly instantaneous. Generally you don't want to do this because you'll end up in a weird state where the service worker install step can be half done or not even done at all and you're expecting some functionality and it's just, now you're way off the rails. You don't want to do that.

JASON: A question from the chat. So with a site that has many pages that people might enter from, so like a blog or something, you would have to load the service worker on every page, is that right?

JEM: Great question, whoever asked that.

JASON: Avh4.

JEM: Great question. No we didn't talk about it. But service workers have an idea about scope. For certain URLs or certain domains you can have one service worker for slash Jason's beard and you can have a different work are for Jem's beard. Because we didn't give it a scope, the service worker automatically inherits down from the root scope. Now we're on local host slash it's automatically going to intercept every single request on every page underneath.

JASON: But then we would still need like on any potential entry page we would need to do the navigator register?

JEM: Yes. That's a good point.

JASON: This would basically be like if you -- you can throw this into your bundle, honestly. Like if you're using a bundler. If you're not using a bundler you can throw it into your script that gets shared across the pages and make sure you include the service worker everywhere. And the other thing to consider is like in most cases, like until you hit an edge case, you will most likely want this service worker to be in the web root. Like at your site.com/sw.js because it can't go up. It can only go down. So if you loaded it like sw.js.assets slash you're going to end up in a situation where your service worker doesn't work because it's only got access to the slash assets routes. You can't put it in your Javascript folder, it's got to be at web root. Which is going to be uncomfortable but it's for all the reasons that Jem just said. The scope is controlled. It's a security measure. Otherwise I can go on, like, what's a website that gives you your own subURL. Like old school my space. If I could install a service worker there, I could go up and take over the whole My Space site. It's a security measure to make sure you're only allowed to control the scope you have access to and not able to step up further in the chain.

JEM: Yeah. Well explained. We didn't touch on security, but that is a good point. Service workers only run on HTS that means you need to have a security on your site. The web moves so fast but most of the modern cool stuff like service workers and audio workers you can only do on HTPS because of security and because this is persistently running in the background, if someone managed to be the man in the middle who knows what they can do. They can sniff out all your traffic, they could do very malicious things.

JASON: That's the evil service worker we were talking about.
Okay. But yeah, so the other thing that's fun here, let's maybe do one that we've got like 5 minutes here. Do you think that we could have our service worker like preprocessed? Like if I put some -- let's say like can we have our service worker fix that text?

JEM: Yeah, I think we can. This one I'll have to look up.

JASON: I would have to look it up too.

JEM: From my quick research, yes we can obviously do that. We take the response from the fetch event, convert it to a blob --

JASON: A blob?

JEM: Yeah. Convert it to -- a blob is a real format. I guess you all know that. Yes, a blob is a real format. Every request coming in is like nothing. I won't say stainless, but it doesn't mean anything to the browser. And depending on the type of requests you're getting a different type of blob. We convert it to a blob and we can iterate over that blob to change things out dynamically.

JASON: Can we do it in 5 minutes? We might be able to do it in 5 minutes.

JEM: Look up exactly how to iterate a blob. This is the senior engineer part. This is where the real coding is.

JASON: Silenced and squint at the screen. What is happening.

JEM: I wonder if I have an example somewhere. I actually just wrote a service worker that does something useful for my actual job, let me pull it up.

JASON: I swear to God, I did something useful.

JEM: I swear I use these in real life.

JASON: If I go in here -- it doesn't actually log out of a full request. Request.body. Oh, there's a lot in here.

JEM: Let's see.

JASON: You would get your response and then you would what? What does that look like? Nothing. It looks like nothing. Might be temporarily down. Did I just break my whole thing? Oh, no!

JEM: What is it saying? Unknown word.

JASON: Oh, I have a thing to be helpful like a spell checker but it's not super helpful because spell checkers don't actually work very well.

JEM: I was going to say I've seen spell checkers in code before and they tend not to work well. Maybe in comments, but no. Because you can give weird variable names.

JASON: There we go. That's what I was trying to do was just log out this response. But my console log isn't working. For any anymore of reasons. Probably the most likely one is that whatever this is isn't actually loggable or it's being replaced. Look at that. It gets pulled out. Which is awesome. How do I get this to persist? I get a readable stream. All right. This is clearly not going to happen within the context of how much time we have here. I just wanted to convert it into text and then mess with it.

JEM: Let me see if I can send you this example. I have an example of doing this but I'm going to send it to you over Twitter.

JASON: Okay. Is this something do you mind if I --

JEM: Go ahead. My secrets!

JASON: Okay. So this --

JEM: Yeah, you got it. So this was just to prove a concept I wrote a long time ago, and what it is is, it transpiles your Javascript code into ES6 code or the other way around, on the fly. So why would you do this and not do it on the server? I don't know your reasonings. I'm not you. But what this does is any Javascript coming down, it checks it. It says hey I'm going to transform this using babble and I'm going to show it to the client. So the client is getting ES5 code, which is pretty awesome. And it's just doing it on the fly.

JASON: Yeah, yeah. That's super cool. I mean, this mostly looks like what I was expecting. So you're taking the request, and then you, we read it out as a blob. That was the part that I was not doing. And once we get that response we can just kind of like do stuff with it, which is pretty cool. So that, I mean that's actually pretty exciting. Because I wonder -- do you think it works if I just do like then get my response and do like response.html there's no way that's going to work, right?

JEM: Let's find out.

JASON: No. It hates that. It absolutely unwilling to entertain that idea.

JEM: You never know. You don't know until you try and it cost us nothing to try.

JASON: Yeah. I mean, this is cool. You can see here that we are getting like here's our response. We get a body. The body is a readable stream. And so we can kind of get in here and start to dig around. So the thing that I thought we were going to do that would be funny it turns out it's actually a decent amount of work. And with that, I think is where we want to kind of draw this to a close. So I think we will -- let's pull this part out. So, Jem, for anyone who wants to follow up with you or follow up on this, are there any additional resources that you want to point people to or places you want them to find you online?

JEM: You can find me online on Twitter @jemyoung and on GitHub don't follow me on GitHub I don't do anything. But I'm on Twitter @JemYoung I use Google developers. Not to dis Mozilla but some of their resources on service workers are a bit pedantic as they do things that are probably necessary but if you're just learning them they're probably not the best way to go. They're probably more advanced. I think it's service worker.rs or service.work or servicework.rs.

JASON: What is this? What buttons am I pushing right now?

JEM: That's right. Worker. So it's an E.

JASON: That's cool. All right. So this is great. Like and like keep in mind service workers they're super powerful. They can be a bit of a foot gun so make sure when you're developing that you're not trying to optimize everything or catch every response. Only catch the thing you mean to catch and be very deliberate about that otherwise you will probably find yourself with reports of a broken website or people who are super confused. And remember if you install a service worker on somebody's site, they have to uninstall it. You can't fix that for them. So you do need to be just be careful. There are ways that you can have your website uninstall, but they'll have to reload a couple of times for that to kick in so it can be a little tricky. Be careful, they're super powerful, great power, great responsibility all those things. Jem thank you so much for coming on today. This was a blast.

JEM: This was the most fun I've had since the last episode of the great Canadian baking show. The highest compliment I can give.

JASON: High praise. Chat thanks for hanging out today. We have some fun stuff coming up. Make sure you check the schedule. On June 2nd we've got Charlie coming back. We had some issues when we were trying to do mind control but we beat them into shape, we're ready to go. We're going come back and do that episode again. Make sure you subscribe and keep in touch. With that being said, stay tuned. We are going to raid and Jem, thank you one more time. We'll see you next time.

JEM: Thanks, Jason.

Learn With Jason is made possible by our sponsors: