Service Workers Practically

Anna Doubková speaking at Front-End London in April, 2017
Great talks, fired to your inbox 👌
No junk, no spam, just great talks. Unsubscribe any time.

About this talk

In this talk you'll learn what service workers are, and why and how to use them in your project. After a quick intro, we'll get into practical examples that you can take and implement in your codebase. We'll also touch on some ready-made libraries that will make your life with service workers easier.


Anna: I'm Anna. I work at Pizza Hut at the moment, as a contractor. There's my Twitter handle in case you wanted to Tweet or get in touch later on. I'm going to be talking about service workers because that's a topic that I'm really passionate about and I'm trying to present everywhere where I go. What are actual service workers? They're this progressive enhancement tool introduced by Google, I don't know, maybe two years ago now. They allow you to do a lot off cool things with your work application that kind of resemble native apps. [00:00:30] For example, they allow you to push notifications to the user as the native app would do. They allow you to add a home screen icon as if you installed the application. They also allow you to this most important thing, which is offline first. You might wonder why Offline first, why it first existed for long enough and it seems to be okay online. Imagine the case that you're on a trip and you're going from station to station, suddenly you don't have any connexion and the website [00:01:00] doesn't load and you see only a dinosaur and you go back, hoping that you can read the previous page but that doesn't load either because everything is offline and you just feel like, why is this happening? I have already loaded this data. This doesn't make any sense. You might also say that this is a first world problem. It's fine because it's just in a tunnel between stations or if you're on a train and there's a bad signal, you know you can survive that. There are three billion people worldwide, especially [00:01:30] in China, India and continental Africa who have very interment internet connexion. For them, it's really crucial to have some sort of a technology that will allow them to load a website and be able to work with it even when they are not online. As an example, that Google quite likes to put out there is AliExpress. I don't know if you know the website. It's an import from China I guess. It's a huge [econ 00:01:56] website and they increase their profits 100%, twice [00:02:00] as much using progressive enhancement because for their market, it absolutely crucial to be able to do offline stuff. I feel like it's not just business, it's also if you want to, say for a more altruistic side of things. If you want to share information with people in developing countries, that can be crucial to them to improve their lives, this technology can really improve sharing this information. I [00:02:30] hope that I sold you on the idea of service workers. They're really cool. Before we get to the practical bit, I would like to tell you a little bit how they work and just get a little bit a feel for what they actually do. I'll put it out there to begin with. It's a bit of a middle man. That's usually a bad thing, right? We don't want middle men. We are trying to get as far away from that as possible but actually service workers are a little bit like [00:03:00] that and they might seem a little bit hacky to begin with. Let's say that this is our client and he is trying to connect to the cloud of the web. Sometimes it works and sometimes it doesn't and he has really no way of telling whether he will connect to the internet or not. It's a little bit of a touchy area for him. That's where our hero comes in. Any sort of like, hello, I can take a look at this request and see if we can do something about it. Normally, what would happen [00:03:30] is, the client would send a request to the web. It wouldn't know that there was a service worker per se. The service worker would intercept this request and decide what it wasn't do with it. Typically, it would send it on to the web. If comes back okay, it saves this data to cache and sends it back to the client. Later on, if then they can't connect to the internet, it will just take whatever is in the cache and serve it to the client. This way we ensure that we have as up to date data as possible and at the same [00:04:00] time, we can serve offline. Another idea that I have used personally before is for performance and that is that when the request is intercepted by the service worker, it can immediately serve something from the cache so that it doesn't have to wait for the request, which obviously means that you might have out of date data, but for example, if it's for a application that only one person ever deals with or works with, [00:04:30] or if you have your personal data, it's okay because you probably know what you have changed. It also kind of works well with Optimistic UI. I don't know if you've heard about the concept where you first update the application as if everything went all right and later on, if something breaks, you go back and say, oh actually something broke, it didn't quite go all right. What is more, the service worker exists after that without your application, without the web and this [00:05:00] is really useful because it can, for example, you have a message app and you send something to the web, and then you close the tab because you thought that it was already updated but then the service worker figures out that you are offline and it can't push it. Well, it can save it and for later one, when you actually go online, it will send it automatically, even if you have closed the tab. This way, it's kind of separated from your application and that's kind of really good because it can do a lot of things that your application normally couldn't do [00:05:30] such as background sync. It can sync data in the background while you are away so that next time you come, it will be completely fresh. This is more or less how it works. There is the middle man and you might ask, just how bad is that. That doesn't sound secure. That's what people say a lot at talks about service workers. They just don't really trust it and I don't blame them because it sounds a bit weird. I go with my intuition [00:06:00] that it might be okay because Google pushed for it and I felt like maybe they've got it kind of right. At the end of the day, it's always better to question even big companies because everybody might make mistakes. service workers work strictly over https. Anything that goes through HTTP will not work with service workers, which can also cause problems. If you know about it, it actually helps you make your whole application more secure. They work a little bit like cookies as in you instal them per domain or per [00:06:30] path. It doesn't even have to be just domain. If you're saving some sort of sensitive data with them, you should probably encrypt them. You kind of approach it in a similar way as you would if you were just saving data normally. They have very strictly limited use. For example, you can't access the window object. Anything that you have on the window, it's not going to work. Obviously, the service worker is installed in the background. It's a worker, as in, I don't know if anyone [00:07:00] has worked with threads before but it's similar concept. It works completely separately from your application and it might not know what the parent location of the user is because the user might not have one. It's more secure that way because it doesn't have access to that many things but at the same time, if you want to use a library, let's say, that relies on window as an object, it might cause issues. Last but not least, it works only [00:07:30] with HTML5 API's. Considering it's only on most modern browsers, it's kind of to be expected. The plus side to this is that you can use the most modern things with that, including the most up-to-date [ES6 00:07:44] etc. It's a really nice thing to work with. You don't have to deal with optimization for all the browser's etc. Finally, to the practical bit. I would like to share some code with you that I created together with some people last [00:08:00] year in Berlin where I ran a workshop on service workers. We put together this application where, at the beginning is just the simple [reactor 00:08:08] that goes and gets dummy stock data and updates them every five seconds. What happens, we were sort of dealing with, what happens in every single case if I suddenly go offline. I tried to load the page when I am offline. I tried to load the page when I am online the first time and then the second time I got offline. It differs a lot. There [00:08:30] are three or four main parts there and we are trying to deal with every single one of them. How many of you have worked with React or are familiar with React? Awesome. It has maturity hopefully. Is that big enough? A little bigger. I'll try that. Or not. It doesn't really work. I'm sorry about that but I'll talk through it a lot. This is a function that we could have in a [00:09:00] loop where we have component [inaudible 00:09:03] when we actually start the application and render component, we will make sure that from that time onwards, we will make every five seconds a request that goes, in our case, to a lambda function that will give us some random data. We turn it into adjacent and when everything goes right, we will set this data into a state. Otherwise, we will see the state as offline true, which basically means there has been an error and we expect [00:09:30] that the error actually means you can't access whatever is on the web. This already you can do with our service workers and it already give you the capability of having your application react to when the user goes offline. It doesn't however help you with the typical case where you refresh the page and you're already offline and nothing loads. That's what service workers are for. You can [00:10:00] register a service worker pretty much anywhere. It works only in the most modern browser's but that's why there's this first line of probe that nobody can read but it says that service worker and navigator so basically, it checks that the service worker actually exists in the browser and if it does, then it goes ahead and it registers it, so you just pass it like a path to the service worker and it immediately registers it and then you just have handling for when it succeeds, someone doesn't succeed, they are just two different consult logs but you can do different behaviours for your application based on whether it succeeds or not. [00:10:30] That one is pretty straight-forward. I would say there is one important thing and that is, when you first register a service worker, it kind of stays there from then on. If you want to update it or something, you actually have to un-register it and re-register it again. That's really annoying when you're developing and I hope that they will change it one day. Their proposition actually is that you don't have to do this. That it will, ultimately it will tell when the file is changed and they will update it, but as far as I know, that [00:11:00] is not happening just yet. Then, there is the service worker itself, which is just quite a simple JAVA script file to begin with. You can just do this, say, let me walk you through it. At the beginning, we add an event lister just like [inaudible 00:11:15]. In this case, it is instal. Then we have some kind of like, we open a cache and then when the cache is open we add all of these things. I'm doing that, it's like, I'm adding forward slash, which is the index HTML. I'm adding [00:11:30] the style, I'm adding the JAVA script, which is the react application itself and an image. The image has a random hash that comes from webpack and obviously, when you rebuild your webpack, it changes the image and you have to change the service worker, which means that you have to somehow figure out a clever integration between webpack and a service worker, which is something that I spent a month doing last autumn. That's one of those things that's sort of really cool. [00:12:00] You can do amazing things with it but the tooling around it is horrible so I think there is a way to go still. There is one interesting thing here, which is the event wait until, which rubs the whole thing. That basically does two things. The first thing is, in case I want to destroy or deactivate the service worker, it will say, actually hold on, I'm still doing something here. Can you please wait until this finishes. Another important thing it does in the instal block is that it [00:12:30] sort of marks the service worker as installing so the rest of the application or the rest of the browser knows that right now it's not available for use. This is a very basic thing and with these few lines of code, you can actually make your application go offline, which is really cool. The only thing that it doesn't do is dynamic requests. You can only do static [fast 00:12:51] with this so it doesn't really help you with going to a lambda or a server and get more information. This is where this comes in, [00:13:00] which is at event list and a fetch. Fetch is this kind of [xhc 00:13:06] thing that you use in HTML5 and this is where we intercepted. We say basically, whenever there comes an event with a request in it, wait here and I will figure out what to do with it. In our case, what we do with it is we carry on with it. We actually make the request. We actually go online and if it succeeds, [00:13:30] we save the things into the cache and if we don't, oh, if we don't is the next slide. This is the happy path where we just save things into the cache. There are a few things that I would like to point out. One of them is that, there is this line that says, only if their URL ends with dot slash get, which, in our case is the address that we use to get the data. I edit that because on our website, we had still [00:14:00] some images that went through HTTP, which completely broke the service worker. It just refused to work with it. This way, I ensured that it sees only the data that I know I wanted to save. Another thing that is really tricky is, there is a response.clone. This is a really interesting thing because the response is a stream so you can't just handle it like an object and put it in two places at once. You have to cone [00:14:30] it. You have to sort of duplicate the stream and send one stream to the cache and one stream to the client. This will help you with the actual, I'm connected and I'm saving data to cache. This part, which is just continuation of the previous slide, is the dot catch part where I'm handling the error. Let's say I go to the server from the service worker and it tells me that, for some reason, it didn't go through. In this case, [00:15:00] I just go to the cache and I get the response from there. See, it's quite straightforward. It's basically like a clever system of caching. The one thing that I'm not showing here because it would get too long, it then allows you to do all of the extra things like pushing messages when the user is offline and then comes online and the periodic sync. It gives you more things that you can work with and really gives you the extra important bit. [00:15:30] If you want to access the repository that I took this from, this is the code. Later on, I will also put the slides online so you'll be able to access that. There are a few more bits and pieces in the code that I stripped off but basically it will allow you to check it out, play around with it, see how service workers actually work and maybe just copy paste and add it to your application. There are a few useful resources. I'll [00:16:00] start from the bottom, which is Jake Archibald's service worker ready? It's kind of not really, sorry. He lists quite a few useful resources, articles, libraries that you can use, although I didn't really find the libraries useful because as you saw, it was already quite simple enough. There are two Redux things. The first one is Redux offline, which is a really simple library that will allow you to sort to plug it in to Redux and it works on its own, which [00:16:30] is really cool. The other one is Logux, which has a similar thing. It's far more clever but it's kind of more like a whole framework with service side rendering etc. If you want to have the fully blown thing, Logux is the way to go. Pro's and con's is my favourite thing to do. I always like comparing the good and the bad. The good stuff is that you can actually create more native like applications, which is amazing. I'm a person. I've done 100 [SDK 00:16:59] and I hated it [00:17:00] and I'm really refusing to learn React Native because it's yet another thing to learn. This actually allows you to do quite a lot of it with just normal JavaScript, which is really amazing. I found it fascinating at the React London conference last month, where Lee Byron was saying, well, we were thinking about service workers at Facebook but we decided against them because they will never catch up with Native log behaviour, which I guess is fair point. It will not catch up with them most likely, probably. [00:17:30] It allows you to get quite a lot of wins, big wins, quite easily. Yeah, and they're awesome. They really help stuff. Obviously, there are some bad things to it as well. Browser support is really bad. It's only on Chrome, Firefox and Oprah, weirdly enough. It doesn't even exist in Safari at all. They're apparently thinking about implementing it but you know, one [00:18:00] day maybe. Even the Android Chrome and the Android browser are not really up to scratch. Right now, it's more like an experimental thing I guess. It can already give you performance wins, which are maybe important for you as well. Speaker 2: Is it not [inaudible 00:18:14]? Anna: Sorry? Speaker 2: It's not in [inaudible 00:18:17]? Anna: It is kind of there but it doesn't work quite as expected as you would expect from Microsoft. Apart from that, there is [battle 00:18:28] [tooling 00:18:28] around it. It's really annoying to double [00:18:30] up for them if you have to register and un-register them. Generally speaking, it feels like the community is still struggling whether they actually want it or don't want it. It will probably take another year or two before you can actually just, like with Redux offline where you can just go ahead, plug it in and not really care about it too much. Last but not least, service workers allow you to store literally anything in the browser, which doesn't necessarily need [00:19:00] to be harmful but if you store a gigabyte of images on a phone, that's probably not going to be great. Should you use them? I think so. I really believe in progressive enhancement and I think that it's quite a win for any application. Obviously if you run this past your project manager, they will say, no, this is not for all users. We don't really want that. We don't want to spend time with that. Maybe if you have a little bit more liberal environment, you might try to go for [00:19:30] it and see how it goes. Thank you very much. Speaker 2: Does anybody have any questions? Speaker 3: Yeah, you were saying about why use them. I'm on the train a lot. I don't even bother. I just save things, literally I save things the night before and I just read things offline because it is not worth. I can't see, I'm probably naïve in some of the cases. I'm sure it's case by case. What we put up things being [inaudible 00:20:00] [00:20:00] than they could be. It seems so useful. The reason I was putting my hand up was, I saw cache is open one and I'm just curious. I saw that on several. What are the different options, if that's at all relevant? Anna: Sure. I'm sorry I didn't go into that one. That's literally just versioning of a cache. You can put literally anything there but obviously if you wanted to make sure that the application is using the right version of the data, you want to upgrade the cache when you upgrade the data. Speaker 3: [00:20:30] That's brilliant. Really great talk. Thank you. Anna: Thank you. Speaker 4: There's one thing that's really scary about service workers and I was wondering if there's any mitigation. My old boss told me that is kind of like, it feels like the third scary thing because the first one is really long-lived HTTP caching, where you can't undo it, right? Once you've shipped that, everyone's got the old version aside forever. Https is the other one where, if you ever want to go back to HTTP, you can't, from https. The third one is to be service workers where [00:21:00] you could get the service worker into a state where you can't download a new version. Anna: Can you actually get that [crosstalk 00:21:07]? Speaker 4: I don't know. That's what, because it looks like it can cache everything. Anna: It can cache everything but you have versions of cache's and the service worker, when it becomes inactive, it closes itself down. Speaker 4: What is inactive? Anna: That is a very good question. I'd like to know that too. From my understanding, it is, there is this idea that when you ship a new version of service worker, the browser will be able to [00:21:30] tell because it has a different hash. I don't think it really works but that's the theory, that the browser will actually tell there is a new version of it and will instal the new version. I think that with new versions of caches, it will automatically be able to tell that the old version is no longer. Speaker 4: The old version can't try and cache the service workers so it never ever downloads a new version. Anna: Well, I actually don't know but it would feel really strange if it could do that because, as I said, it had really limited things, limited [00:22:00] optionality's. Speaker 4: Okay. Anna: Interesting, I'll try that one. See if I can break it. Thanks. Speaker 5: Yeah, you mentioned the caveat that it's https only. I was just wondering if that has any implications for when you are working locally and just in terms of the local development flow, how does that work? You probably need to be clearing your cache a lot and just testing things out. Anna: It's exactly the same thing as when you are working with any other https. It just works locally on HTTP if it's local host, but the moment you go online, [00:22:30] or on the web, it needs to be https. It's fine too, for development in that sense. Speaker 5: Okay, great. Anna: I'll say, I find it interesting that a lot of people say that https is a caveat. I'm sorry, did I catch you on the word, but maybe not personally you but there are some people who say, but it's only https and I feel like, but that's a good thing. That's really great. Anyhow, yeah, I just wanted to point that out. Is there anything else? Yeah? Speaker 6: [00:23:00] Do you think there are any chances of browsers implementing sort of an automated service worker into their general system so rather than having to write your own, it would become part of say, Chrome's general caching or is that sort of years ahead and a bit too complicated to actually accomplish? Anna: I'm wondering if that's something that you would actually want to because you already have kind of a static cache, right? Available [00:23:30] locally. Obviously if a browser decides to do this on their own, then as a developer never have any control over what actually the user sees. We are already experiencing a lot of problems with that because if the user opens a website on Friday, we should fix it by Monday but they haven't reloaded the page since Friday. It's already out of sync so I'm wondering whether there is actually a point to that. Speaker 6: One thing that I would just [00:24:00] add to that is that browsers have a lot of rich history of different kinds of ways of storing big stuff online, offline, onto the client, index db and other ones as well. The problem with those, obviously, was that the different browsers supported them differently and not particularly well. The other one was that there's a lot of problems with just the logic of how do you maintain that state. I think that's really where a service worker came in, [00:24:30] in trying to give the developers of the owners of the websites and the web applications, the ability and the power to actually decide when something needs to be refreshed and when not. I think that's really just a little bit of context of where our service workers came from. Anna: Thank you. That is really useful. Any other questions out there. Yep, one there. Speaker 7: I was just wondering if you had any tips on how to test the logic in your service worker because there isn't [00:25:00] really any libraries or anything for it at the minute. I was just wondering what you did. Also, one little thing. There's a checkbox in the application tab of Chrome dev tools to make the service worker update on reload so you don't have to register [crosstalk 00:25:14]. Anna: Yeah, it didn't seem to work half a year ago when I was working with them most. Speaker 7: Basically, now everything needs two refreshes instead of one. Anna: Yeah, exactly. Okay, right so yeah, there's that option but it kind of worked 50% [00:25:30] of the time and I wasn't quite sure why. That's part of the problem with service workers because you can't really go in them and see, why is this happening, because you don't really have much control over them. Sorry, what was the question? Speaker 7: About tips for testing them. Anna: I didn't test them. I must admit that. I wasn't TDD at all. I wonder how to do that. I guess my approach if I wanted to do it now would be sort of rapid and a function [00:26:00] where you would pass these things as parameters and set them to the default ones and then when I test it, I would pass stubbed ones or mock ones but yeah, obviously, that's not ideal at all. It's definitely one of those things that, I would say that the tooling is missing that a lot because doing this yourself seems incredibly painful. You're totally right. Speaker 7: What is the web pack storing? How do you bundle your application and get automatic service worker registering? [inaudible 00:26:30] with [00:26:30] those bundles? Anna: Sure, so there are tools. I think it's called web pack service worker, obviously, but I found that it didn't really work for my use case where I needed to fill a packet with some other dependencies so I ended up having to work back on [figs 00:26:49], one for service worker and one for my normal application and we just did it manually, which is not ideal at all. I know that there is a web pack library for it but it never really [00:27:00] worked as expected. Maybe it has moved on but there is a way of doing that automatically, yeah. Speaker 8: It's called offline plug in. Anna: Offline plug in. Speaker 8: It works great and it solves all of the things that you were saying were very hard about caching validation, like changing the number of ... This is why I didn't want to ask a question because it's not a question, it's a statement. Because it's part of your pipeline, it's aware of all of the assets that are going through it. When [00:27:30] you have versioned Jpeg's, for example, it knows what the name of the jpeg now is. Anna: That's amazing because I did this in September and I felt like it didn't do that at all. Maybe they've improved it or maybe I just missed that, but that's great. Speaker 8: No, it's wonderful. It will change your life. All of the stuff that you were saying that's kind of a bit miserable about registering the thing, that's all handled for you as well and if you opt into the event hooks, then, for example, when [00:28:00] it automatically detects that there's a new version of the work, which solves your concern about problem three. It really does work too, it will automatically download the new version of the service worker. It's not very good at giving you a hook into your reactor but you do something dumb, like just reload the page. Anna: Wow, that's great. Thanks for sharing that. It's really good. Speaker 2: Thank you very much. That was a really great talk. Anna: Thank you.