Service workers bring amazing new capabilities to the web. They make fully offline web apps possible, improve performance, and bring more resilience and stability to any site. In this talk, you'll learn how these man-in-the-middle attacks on your own site work, different approaches you can use, and how they might replace many of our current best practices.
Service Workers: How to Run a Man-in-the-middle Attack on Your Own Site for Fun and Profit
AI Generated Video Summary
Service workers provide resilience and make sites faster by intercepting requests and responses, caching assets, and providing fallbacks. They can be used to show critical information when a site goes offline, cache pages for offline access, and improve performance. Service workers can also be used to build multi-page apps with more resilience and less complexity. Caching API responses and gradually adding more complex features are recommended when adopting service workers. Single-page apps are not always the best choice, and different approaches fit different use cases.
1. Introduction to Service Workers
So what I wanna talk to you about today are service workers. A newer-ish tool in our toolkit that we can use to provide more resilience in the things that we build. Service workers can make our sites faster and allow us to build websites and apps that continue to function even when things go wrong.
2. Service Workers: Strategies and Examples
Here's the agenda for today's talk. We're gonna spend a bunch of time talking about what service workers are and how they work and then we're gonna dig into some specific strategies you can use when implementing them. Finally, we'll take a look at some cool things that you can do with them. I always find that looking at specific tangible examples helps make this stick. We are going to look at code, but we only have about 18 minutes left and you can easily fill an hour-long talk with just code examples, so we're gonna stick to some pretty high-level surface examples.
What makes service workers really powerful is that they have a built-in storage mechanism. They have a cache and it can hold a lot of stuff, way more than local storage or cookies can. And you can actually take those responses that come back, save copies of them in your cache. And if something goes wrong with the network, you can load assets from your locally saved cache instead of the network, or cut it out altogether if you want. A service worker is a man-in-the-middle attack on your own website, but like a good one. Now obviously there's a lot of potential for abuse with something like this. So service workers require browser encryption and SSL certificate to work. There's an exception to this made for locally hosted sites. So if you're just running it on your laptop to test it, you don't need a certificate for that.
3. Service Worker Strategies
As soon as your website is live, you'll need an SSL certificate for the service worker to work. There are two strategies: network first and offline first. Network first checks the network for responses and saves a copy in the cache. If something goes wrong, it checks the cache for a saved version. Offline first checks the cache first and then goes to the network if needed. Both strategies use the respondWith method and the fetch method to handle requests and responses. Network first is best for frequently updated assets, while offline first is best for static assets. Service workers can also provide fallbacks when things go wrong.
But as soon as it goes out on the web and you visit it with a URL, you're gonna need to install an SSL certificate or the service worker won't work.
Let's take a look at some service worker strategies. There are two basic approaches that you can use, network first and offline first. With a network first approach, you initially check the network to see if there are any responses. And if you get one back, you pass it through to the browser, probably saving a copy of it in your cache. If for some reason something goes wrong and it can't find that asset or your site goes offline, you can check the cache, your local storage, to see if you have a saved version of that request. And if you do, you can send that along instead.
And here's what the code for that looks like. Once again, we're using the respondWith method to send a response back for that request, but this time we're checking the app cache first to see if there's anything stored there that matches the request. If there is, we send it back, but if not, we use the fetch method again to make a live call to the network for that response or for that request rather. And when we get it back, we can clone it, save it into our cache and then return the response.
4. Caching and Fallbacks
If you get nothing back, you check the cache. If you still find nothing, return a different asset. For an offline first approach, check the cache and then the network. If nothing is found, send a fallback. Code example: listen for the install event, open a new cache, and make a request to save assets. In the fetch event listener, check if the request is cached. If not, send the cached offline HTML document.
If you get nothing back, you check the cache. And if you still find nothing back, you can return a different asset. This could be something that you downloaded when your service worker installed for the first time. You may preemptively cache some fallbacks for when things go wrong, or you could make a live call to the network in real time.
With an offline first approach, you do the same thing, but in reverse. You check your cache, you don't find anything, you check the network, and if you still don't find anything or you can't reach the network, then you send along a fallback instead.
And here's what the code for that might look like. When a service worker installs, it actually triggers an install event inside the service worker file itself. So you can listen for that with an event listener. And when that happens, you can open up a new cache and make a request to whatever assets you want to save with the new request constructor. And so in this example here, I'm requesting the offline HTML document that I want to send to people whenever they can't find pages. And then inside my fetch event listener, inside the catch handler, I am going to check to see if that request is cached. And if for some reason it's not, then I'm going to send back the offline HTML document that I have cached instead.
5. Uses and Examples of Service Workers
Service workers can be used to show critical information when a site goes offline, cache pages for offline access, and improve performance by caching core assets. They can enable fully offline functionality for apps and games and can replace single page apps with more resilient multi-page apps. Service workers provide benefits such as faster page loads, reduced API calls, and improved user experience.
Let's take a look at some uses and examples of service workers. This is where I think things really start to stick. So a really low hanging fruit here, the example we actually just looked at, is showing critical information when a site goes offline. So if someone loses connectivity entirely, you can still give them a usable experience. And this is really particularly useful for things like restaurants, conferences, and hotels. With a restaurant, for example, you might let the user know they're offline and then give them other things that they might need or want from your restaurant. Phone number, an address, or directions on how to get there. Maybe an abridged menu and a phone number to call to make reservations.
For a conference, you might have the schedule for that conference, the venue, and the name of the organizer in case someone needs to get in touch with someone and just can't get the webpage to pull up or they're having connection issues, which is pretty common in hotels and conference venues where a lot of people are using the Wi-Fi and things kind of break or go down. Extending this a little bit further, you can cache pages in real time as people visit them, and then if for some reason they go offline, you can show them a list of the pages they visited and make those available to them even though the site is offline. And this is particularly useful for reference sites, news sites, social networks, utility apps, just because the site is offline doesn't mean people can't still use it and access things that they've already been to.
6. Handling Page Navigation and Accessibility
Handle forward and backward button clicks. Update document title, shift focus or scroll position. Ensure screen reader users are aware of page changes.
You need to handle forward and backward button clicks, which again, a lot of single page apps just kind of forget about. Update the document title, shift focus or scroll position on the document depending on where someone's supposed to be. Again, a thing a lot of single page apps break. And then you really want to shift focus back to either the document or more ideally the heading element so that screen reader users get an announcement telling them that the page has changed and they know where they are. This is another thing that a lot of single page apps forget about and break and make the experience bad for their users rather than better.
7. Benefits of Multi-page Apps with Service Workers
Multi-page apps, when paired with service workers, provide the same benefits as single page apps but with more resilience and less complexity. Static site generators aid in pre-rendering HTML files, which can be cached with service workers and paired with CDNs for faster experiences.
8. Caching API Responses and Building Multi-page Apps
When using Service Workers, you make a call to an API and cache the JSON response in the service worker's cache. This allows subsequent requests to be loaded from the cache, providing an instantaneous response. Multi-page apps can be built using statically rendered HTML and API data served from the cache, resulting in a fast and resilient experience. By using Service Workers, we can build a faster, more resilient web.
Now, when I talk about this, I always get asked about the API piece of it. So you're making a call to an API and with a single page app, that would just live in the browser memory and you never have to worry about it again. But with a service worker, you still make a call out to the network just like you would the first time because you load a single page app and then you cache that JSON response in your service worker's cache instead of just trying to hold it in memory for the entire session. The caveat here is that you usually wanna put an expiration date with it. So you want this to eventually go away either when the user logs out or when the session ends or after a certain period of time. And then every subsequent request, every page load for that API, you load it from the service worker cache instead of reaching out to the network. And this effectively gives you that same instantaneous response that you would get if you were just holding it in browser memory, but without all of that developer overhead.
If you found this talk interesting, I put together a bunch of resources for you on Service Workers over at gomakethings.com.js Nation. You can find the slides from this talk as well as a ton of related articles, podcasts, books, and more. Thank you so much. It was really great chatting with you. Whoop, whoop, whoop, whoop! That was such a good talk. I want you to go over into the community channel and throw us your best emojis to congratulate Chris on such an amazing talk. Really, really loved hearing it. And also, one thing we're gonna need to do before we move on is we need to go and find out the answer to the question that Chris posed. Chris asked us, tabs or spaces? And I'm just gonna get the poll up right now and check what the answer was. So, tabs or spaces, and we can see that a majority of you wonderful people have said, let's see, tabs, which is brilliant. Thank you, you're like-minded, you're just like me. I'm legitimately, I'm both pleased and surprised by this.
Discussion on Service Workers and Q&A
I'm bringing in Chris now. Chris, thank you so much for that talk. We've got lots of questions coming in. Can I intercept or get requests for a particular API endpoint and modify a search parameter? Yes, you can. You can use the fetch method in your service worker to modify the request and pass along the modified result. It's like a man-in-the-middle attack on your own site. And yes, I have a tutorial on ServiceWorkers.
I'm bringing in Chris now, so you're pleased and surprised. So what do you choose usually yourself? I'm tabs, I'm tabs all the way. Chris, I like you already, I like you already. It's just objectively the best, but- Absolutely, what are people with spaces doing? It's efficiency, pressing it once versus pressing it four times, come on, I'm joking. I am very passionate about my love for tabs. They were all developers here.
But Chris, thank you so much for that talk. We really appreciate it, and we've got lots of questions that are coming in. So make sure also if you're listening and you still have a question that you wanna ask, drop it into the chat, into the Q&A channel, sorry, right now and we will make sure we get all of those asked. So I'm gonna go straight from a question that we have from Alexius, who asks, can I intercept or get requests for a particular API endpoint and add or modify a search parameter of this request? Sort of, yes. So, and I reserve to be completely wrong here because I haven't tried this myself. So browsers may throw up some sort of like security thing around this that I'm not aware of, but the limitation here with API requests is with service workers, you can only intercept, get requests, not posts, puts, deletes, anything like that. But using this approach, you could theoretically get the request and then use the fetch method in your service worker to call that same endpoint with a changed parameter or an additional parameter or some sort of like additional variables put on. And then when you get the result back, pass that along. You don't even have to cache the result. This could just be a thing that you do in real time as a way to as the title of my talk suggested, run a man-in-the-middle attack on your own site. But yeah, conceptually you can absolutely do that. I'm not aware of whether or not browsers might, raise their hackles a little bit about the idea of that kind of thing for security reasons. But I believe that that is absolutely something you can do.
That's awesome. That's awesome. I love when you talk about it as a man-in-the-middle attack on yourself. I don't know why it just makes me laugh. And we've got another question. And this one I actually wanna know the answer to as well. CRS 1138 says that this is a cool talk, but have you got a tutorial on ServiceWorks? You know so much and you're really good at explaining it. Right? Great question. Let me find out. That sounds like a really silly thing to say. I write so much that, yes, I do.
Service Workers Adoption and Caching
I have a handful of recommended resources, including books like 'Going Offline' by Jeremy Keith. When adopting service workers on an existing code base, it's best to start with basic functionality and gradually add more complex features. For example, caching frequently accessed assets can provide a performance boost. When it comes to invalidating cached files, service workers automatically update files if they detect a difference, but the new version is only used after all tabs with the site/app are closed. There are tricks to force the use of the new file sooner. I'll share a link to an article with more details.
I have a handful of them. I will make sure, it looks like I have nine. So I will drop them in the Discord when this Q&A is done, and I'll make sure to reply directly to your message so that you see it. Yeah, because I have a whole bunch of them. I also have some recommended books and other things like that, that you can also check out. Specifically, Going Offline, by Jeremy Keith, is where I learned a majority of what I know about service workers. And it's an amazing book that I highly recommend.
And someone's asked, speaking of caching, they say caching is the best thing for most use cases, yes. But can you please help them understand how and when they should invalidate things? If there is a new version of the site, how effective would it be? And is it easy to implement? Yes. Yeah, great question. I didn't really touch on this all in the talk at all, time limitations and all that. So service workers are super magical in that every time the browser loads one, the service worker itself is also cached. But whenever it loads, if there's an internet connection and the browser can grab the newest version of the file, the file name doesn't even have to have changed. It just will find the current version of the file and compare it to the existing one. And if a single byte of the new file is different from the one that it has cached, it will, in the background, replace the old file with the new one and automatically update that for the user. There are also some caveat here is it won't actually use that new file until the visitor has completely closed out any open tabs with your site or app in it. There are some tricks you can use to force it to start using the new file sooner before that install process happens. The code for that is actually in one of the articles as part of a series that I wrote. So I'll make sure that I drop a link to that in the residence track Q&A so you can access it, just because the URLs get kind of too long for me to read out loud here.
Service Workers Q&A
The code for that is actually in one of the articles as part of a series that I wrote. You know you're really good at educating people on the internet whenever you answer a question with, I have an article for that. We got another question from Kev that are saying that this is a great talk. And I guess you can also use a service worker to mock an API get request. And Tom Rafa also asks, are there any situations where you would advise against service workers apart from fetching frequently to update data? No, service workers are for everything. There's a very extreme end where you're caching everything and just going straight to the cache first. And then there's the more lightweight experience where you provide some sensible fallbacks. And then there's a whole range of stuff in the middle. Yeah, I also get that, where you've got a balance of what's the ideal thing that you can create, and then actually how much time and resources you have to get there. And when you spoke earlier of the gradual approach, being able to use your resources to slowly bring that in, it makes so much sense. And then someone asked the question, which I think is quite interesting, why is it that not many apps go service workers and offline first in the real world? What do you think is stopping a lot of other websites from implementing this approach? I think a couple of things. First of all, they're not really new.
The code for that is actually in one of the articles as part of a series that I wrote. So I'll make sure that I drop a link to that in the residence track Q&A so you can access it, just because the URLs get kind of too long for me to read out loud here.
You know you're really good at educating people on the internet whenever you answer a question with, I have an article for that. That is so awesome.
We got another question from Kev that are saying that this is a great talk. And I guess you can also use a service worker to mock an API get request. I'm pretty sure you can do that, right? Oh, that's a great question. Yeah. So theoretically, if someone kind of calls an endpoint that may or may not actually exist, you can intercept it and then respond with, like you don't actually have to make a live call anywhere. You could create a new response using the new response object and send back whatever data you want. Yeah, absolutely. That's actually kind of a neat thing that I hadn't really considered before. Yeah. That sounds like an interesting way to use it.
And Tom Rafa also asks, are there any situations where you would advise against service workers apart from fetching frequently to update data? That is a good question. Where I would recommend against service workers. No, service workers are for everything. Service workers are one of the best things to ever happen to the internet for a variety of reasons. I think there are different use cases for service workers. And so the way you implement it in a particular situation might be different from another. So caching aggressively might not always be appropriate for all the things, for example. But I can't think of a single use case where a site or app wouldn't benefit from having some form of service worker, even if it's just doing a little bit of stuff. There's a very extreme end where you're caching everything and just going straight to the cache first. And then there's the more lightweight experience where you provide some sensible fallbacks. And then there's a whole range of stuff in the middle. And which strategy you choose is going to depend heavily on what your app does and how much time your team has to commit to building out this approach.
Yeah, I also get that, where you've got a balance of what's the ideal thing that you can create, and then actually how much time and resources you have to get there. And when you spoke earlier of the gradual approach, being able to use your resources to slowly bring that in, it makes so much sense.
And then someone asked the question, which I think is quite interesting, why is it that not many apps go service workers and offline first in the real world? What do you think is stopping a lot of other websites from implementing this approach? I think a couple of things. First of all, they're not really new.
When Single-Page Apps Are the Right Choice
They're newer than a lot of other things that we have. But I don't feel like they're as well known as some of the other kind of technologies and solutions we have. And I also feel like for a really long time, single-page apps have been such a thing that that's just the tool people grab for a lot of things. And so a lot of what we do on the front end, not just not using service workers, but just a lot of the choices we make, often feel like a byproduct of developer inertia rather than necessarily being the best tool for the thing we're trying to accomplish.
That makes sense. I mean, I'm not going to lie. I remember when one-page apps came about. I loved them. And this is kind of a question that I have for you as well, is because you spoke about how, like, sort of single-page apps can be bad for a couple of different reasons. But what would you say are the times when that's actually the right way to go?
Service Worker Deployment and Tutorials
Someone asked if you usually notify the user of a new version or wait for the service worker to be reinstalled. For basic service worker usage, I haven't found a need to notify users. My service worker changes are usually not significant enough to warrant immediate browser reloads. You can use the post message method to send events to service workers and react accordingly. If you want to learn more, visit gomakethings.com/JSNation for tutorials, articles, books, and more resources on service workers.
We got so many more questions. People love this talk. Someone asked, would you usually notify the user if a new version is deployed, or would you just wait for the service work to be reinstalled in the next session? So I say this is someone who uses service workers in a very kind of basic and lightweight. I've not really found a need to do that. Usually, the changes I make to my service workers are not substantive enough that they warrant like you need to reload the browser right now to like make this thing kick in. Or I can force it to kick in kind of behind the scenes. Usually what's happening with my service workers is they're just kind of caching assets as they come through. And I may make an update that caches some additional stuff or stops caching some stuff I was caching before. But they're not doing the kind of like this will make or break an application type of work that requires me to like show notification for a user. There is a way to do that. Using the post message method, you can actually send events to service workers and then from service workers back into the client. And in both files, you can listen for these events and kind of react to them accordingly, which is pretty neat. So if you did wanna do something like that where you like show a message in the browser, that's absolutely something you can do.
I'd love to check that out. Actually I've never actually thought about sort of that, using it in that way. Now I bet I'm gonna go and Google it and find an article from you about it. But thank you so much, Chris, it's actually been a pleasure to talk to you and to learn because you're so knowledgeable about service workers. But since you spoke about the tutorials you write, where can we find those tutorials and where can we find out more about the things you write about? Yeah, so I would recommend if you would enjoy this and you wanna learn more, if you head over to gomakethings.com slash JSNation, I have put together a ton of resources on service workers, recommended articles, books, forms to sign up for my newsletter, as well as the slides and video from this talk. So you can find that all on my website.
Awesome, thank you. And Amit is so nice, we have perks from companies and sponsors but we even have perks coming from speakers too. So definitely check out his website and I'm going to check out right after this event. I'm super excited, but thank you so much Chris for hanging out. I hope you've enjoyed it. I have, it's been a blast. I'm going to head over to Spatial if anybody wants to chat. Cool, yeah, definitely join Chris in the Spatial chat. The link will be in the timeline below. See you there, Chris. Cheers.