Check out a free preview of the full PWAs: You Might Not Need That App Store course
The "Creating a Service Worker" Lesson is part of the full, PWAs: You Might Not Need That App Store course featured in this preview video. Here's what you'd learn in this lesson:
Maximiliano demonstrates how to create a service worker file, register it in the index.html file, and debug the service worker using the browser's developer tools. He also shows how to use the fetch event listener in the service worker to intercept and respond to network requests.
Transcript from the "Creating a Service Worker" Lesson
[00:00:00]
>> Maximiliano Firtman: Let's go to Code, and let's write our first service worker. So first, to create a service worker, a service worker is just a file, so just a new file. I will call that fileserviceWorker.js. It's a JavaScript file, okay? And then will say console.log I'm a service worker,
>> Maximiliano Firtman: Ready to serve, whatever, okay?
[00:00:23]
It's just some code. So, how can I include that file? Well, I can go to my index.html and add a script tag, but that's not how you register a service worker, okay? It's just a normal script, so that's not how that works. What I need to do is, I can write a script here, or I can create another script and write it there.
[00:00:45]
It doesn't matter. navigator.serviceWorker, be careful with capital W, .register, and we pass the name of the file. This is really important by default the scope of the service worker is the folder in which it's defined, which means don't do this, don't create a folder, scripts, and put the file there.
[00:01:21]
If you do that, then the scope will be the scripts folder. So we were responsible for that folder only, okay, make sense? That's a common error, a common mistake that you make initially. So now, typically, the service worker goes to the root. I mean, you can override that, but it's kind of complicated, that's another.
[00:01:41]
It's one file, and that's all. By the way, if you wanna use ES module, ECMAScript module, by default, it's not a module, so you cannot import from other files. It's a worker, so you can use importScripts API, I'm not sure if you have used that before. But this is a web worker API, so it's been pretty wide.
[00:02:01]
But it's not really ES modules. If you wanna use ES module or treat that JavaScript as a module, when you register that, you have to add another argument and you say type: "module",
>> Maximiliano Firtman: Like that, or I did It didn't close the string like that, okay? So in that case, now that service worker, it will be treated as an ECMAScript module, and it can import from other modules, okay?
[00:02:34]
No need for today's sample, okay? I was just showing you the idea. I will just comment that. I mean, it's not gonna make any difference, but anyway. So, is that that? Is that that? Are we ready? If I go to localhouse:3000, I don't see any difference, okay? If I inspect and go to the console, well, I'm getting an error for five icon, which is okay, it's a problem.
[00:03:01]
[LAUGH] But here, it says, I'm a service worker ready to serve. So somehow it appeared. But something even better is to go to the Application tab. And we already know the Manifest section, there is another section for service workers. And here, you can see that the service worker 16,005 and is activated and running.
[00:03:24]
And this is my service worker. So now, I have a separate thread that can see all the network requests that I'm doing and I can also serve assets. So now, something interesting that I have here in the service worker debugging section is that I do have an offline simulator.
[00:03:49]
So instead of turning off the WiFi or turning off the server, I can click here, Offline, refresh and see what happens. So is it offline capable? No, look at that. That's my default offline new page that Chrome is implemented. You are offline, okay? We don't see, unfortunately, I'm sorry little, you're gone.
[00:04:12]
I mean, you have your Dans counted, but at least you have that, okay? But it's not working offline then. I mean, I'm getting something, yeah, I'm getting something better than before, but the website is not working offline, okay? I'm getting a better response. So now, if i even open the the app from here, but this was the previous loading.
[00:04:36]
Let me open it up again, so this is what you see, okay, but I think it was a bug. For a second, I thought we had just found a bug. But the app is not really available offline, because something important for the service workers is that they don't do anything automatically.
[00:04:57]
So yeah, I have a service worker, I have a thread, but it's just sitting ducks there, it's doing nothing. I need to manually write my service worker. So that's why you should first cache the resources. So the service worker has a local cache, it's called the cache storage API.
[00:05:22]
We can cache all or some of the reasons you pick, okay? Everything is based in JavaScript promises. Typically, we prefetch on installation, so we can wait for the service worker to be installed, and we prefetch the assets. Okay, I need the C mesh. I need the CSS, I need this HTML, and then we can also cache on request.
[00:05:47]
So you know what? I'm not going to cache anything. When the web app needs something, I will go to a network and make a copy of that for next time. Okay, so different patterns that we have available for caching files. And this is known as the app shell pattern.
[00:06:04]
It's a design pattern where when you install a PWA, you go and grab all the assets that will render the app shell. If you're using Angular, for example, Angular supports PWAs. There is a a plug-in in Angular, I'm not sure. For those of you that know Angular, you know what I'm talking about.
[00:06:23]
It's a schematic actually, you can add a PWA schematic, and there is another one for the app shell. So then you can create the app shell that then the service worker that Angular creates will download all the assets to render the shell without the data, okay? It's just that.
[00:06:43]
And then you need to serve those resources. In the service worker, we respond for every request that PWA make, every request. In fact, let me prove that. Before actually making a service worker that actually works, let's add something else here. I'm going to add this. First, the service worker is not the window.
[00:07:07]
Let me prove that. It doesn't have access to the user interface. Let's refresh here. So for example, if I say this here is the window, okay, you have probably seen that. But I'm not sure if you know, when you are executing code in DevTools, you have a selector here where you can select another context.
[00:07:29]
For example, I have the service worker that is currently activated. So I can go now to that thread and I can execute now code under the serviceWorker. And that's the serviceWorkerGlobalScope. If I try to make an alert, hello, it doesn't work. It says, I don't know what an alert is.
[00:07:47]
Because I'm in the serviceWorker, it has no UI. If I go back to top, of course it works. So you can change the execution context based on that, okay? So, what we can do is we can add an event listener called fetch.
>> Maximiliano Firtman: I'm attaching this to the global object that here is called self.
[00:08:11]
Or now with ECMAScript, you can use globalThis. If you don't know about globalThis, you can check Professional JS course in Frontend Masters, where we cover all the latest stuff in ECMAScript, where we cover globalThis. But if not, you can use CELF. So I can say, console.log File request.
[00:08:34]
Well, actually, more than file, HTTP requested.
>> Maximiliano Firtman: So now, first, before actually reloading, what do you think that will happen with the serviceWorker? Will take my new service worker, because the service worker is already installed?
>> Student: You have to disable the cache in the browser.
>> Maximiliano Firtman: But you will see what I need to do.
[00:09:02]
But first, it's important to see if you understand the problem. The serviceWorker is always installed in users devices. So if you change it's server side, by default, it's not going to take it. It's using the old one, okay? It's like my iPhone, where I don't update my apps.
[00:09:20]
I still have the old one. It doesn't matter if you change it in the app store. So, there is an update process, an update algorithm for the serviceWorker. Actually, what will happen is that when you open the app next time or when you reload, it will check in the server and download the serviceWorker.
[00:09:38]
The browser is doing that, and it will check byte by byte. So it will do a byte by byte comparison with the serviceWorker that is installed to see if it's is new one. If it's a new one, it's not going to push this one, okay? This one will be installed and it will be waiting for be activated, because this one is already active, the old one.
[00:10:00]
And in the current navigation, the old one is in charge. But when you close the app, 40 seconds has passed and this one is discarded. The next time, the new one is going to be the one that be activated, okay? I'm just simplifying here a little bit this, because service worker is a complex concept, so it takes time, but just to give you quick ideas of what's going on.
[00:10:24]
That happens unless you have the DevTools open with this check mark checked, update on reload. When you hit update on reload then this algorithm that i explained is not gonna happen. But you refresh, the service worker will refresh as well, immediately. But that's not what will happen in the real world with real users, okay?
[00:10:48]
Make sense? So now if I refresh, I go to the Console, I'm a service worker, ready to serve. And now I see nothing. Why I'm not seeing nothing? Because it's already registered. So nothing happens, because it's already registered, okay? And now, 6 HTTP files were requested. Can you see that?
[00:11:13]
Yes, okay, can I see which files were requested? Well, the event, I can convert this into a template string.
>> Maximiliano Firtman: It has request and the request has a URL.
>> Maximiliano Firtman: Okay, so if I refresh, it's not taking this. But now, look at this, it says this and then this, because the new one takes time to be registered.
[00:11:41]
The bagging service worker takes time because you have the old one, the one that is in memory, then you refresh, it's trying to replace the other one, so there is a life cycle going on. It's not so simple, so direct as before. Sometimes they say, you need to refresh again.
[00:11:59]
In the Application tab, you can go here to Service Worker and you can see that even if you refresh, there is one that is waiting to activate. So I'm still working with the old one, because it's in memory. Does it make sense? So it's in memory, so it's not killing the process.
[00:12:15]
So unless i hit here, Skip waiting and now the new one is in place. Does it make sense? So it's a complex thing that you need to try here. So now, if I refresh, finally, I'm seeing the request. And look at this, this is really interesting, because I'm seeing all the requests.
[00:12:36]
And you can see that it's requesting app.js, but it's also requesting PWA compat, that is not really my domain. So the service worker, the proxy, it's also seen, requests that are going somewhere else, and that was actually part of the diagram that we saw before, this one. So the service worker is seeing not just my server's request, but also requests to other places, okay, and it can reply.
[00:13:09]
That's the important part in the name of those servers as well. How? I'm going to do this quickly. This is not a real code, it's just for testing purposes. Event has a method, respond with, respond with. It accepts an HTTP response or a promise of a response, okay?
[00:13:35]
So that means I can create a new response and the body of that response can be, hey, hehe.
>> Maximiliano Firtman: So now, I'm responding, actually, to every request with that response. I'm kind of Express.js here, so I'm a server now. I'm creating an HTTP response, okay, client side. Because it's a JavaScript client side, so I don't have Node.js here.
[00:14:05]
So first, if I refresh, I'm still not seeing that, because again, we have the same problem as we saw before, okay? We have one waiting for activate. You can always go to Storage also and clear everything that will clear service workers and blah, blah, blah. But if not, you can skipWaiting, refresh.
[00:14:23]
And now, I see, hey, hehe, I'm not even seeing the HTML anymore. And what about if I try other URL? Just the same. Why it's not giving me 404? Because now the service worker is in charge. The service worker is taking every request to its scope, which is localhost:3000, and answering the same thing.
[00:14:50]
And we can go to the network layer, the Network tab, refresh, and let's go to all here, and I can see the request with the headers. I'm requesting this. Here, you can see the status quo, hey, hehe. You know what? It wasn't a real server. It was a service worker, but it's kind of a metadata hidden there.
[00:15:13]
It's still a response where I have all the headers. I have the response headers, and of course, I can customize from the service worker. But from a network point of view, it was the server once or that. Quick trick, when you reload, if you press your Shift key, so Shift+Reload will bypass the service worker, just's for that reload.
[00:15:37]
Shift+Reload, I reload service worker. Shift+Reload, no service worker, okay? So that's a quick way to, when you are testing, you can bypass the service worker quickly. So you can see that the service worker is a serious thing. You can break your website with one line. One line of wrong service worker code, and your website is broken.
[00:16:01]
I cannot even browse my website anymore.
>> Student: More of a curiosity question. It kind of seems like it's an app-level client implemented forward proxy. Have you seen in the wild service workers being used for non-PWA purposes, inspecting from the browser outgoing requests, or like-
>> Maximiliano Firtman: I mean, you can, but you can also do it in the main thread.
[00:16:33]
So I mean, it's not a security risk, but you can log every request. You can add a security layer. The service worker for performance reasons is being used a lot. There are a lot of tricks and design patterns on the web performance field that can help you with that.
[00:16:50]
But yeah, but not initially, okay, with that in mind.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops