تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Introducing Service Workers0:00

Let's make our app work offline. To make our app work offline, we need what's called a service worker. It's just a special JavaScript file that the browser loads, and it doesn't have access to the page or the DOM or anything like that, but it does have access to any request that's made. It can cache data. It can even receive push notifications. It's a very powerful JavaScript file, which is one of the reasons why it can only work with HTTPS.

It's a very powerful JavaScript file, which is one of the reasons why it can only work with HTTPS. Well, I say it can only work with HTTPS. If you are developing your application from local host, then it can be HTTP. But in today's day and age, with the tools that we have, it's just easy enough to flip a switch to HTTPS and run with that. So in production, you will need HTTPS. I guess I should have clarified that in the previous episode.

Creating the Worker File1:03

So in production, you will need HTTPS. I guess I should have clarified that in the previous episode. But anyway, it's a powerful JavaScript file, and you can think of it as a programmable proxy, because it essentially sits between our app and the network. Well, it's really cool. So let's create a service worker, and I'm going to do this inside of the public folder. Now, where we create this service worker is very important. I'm going to call it sw.js.

Now, where we create this service worker is very important. I'm going to call it sw.js. The name doesn't matter, but where we put it does, because it determines the scope of the service worker for the most part. Now, it's not the scope of variables or functions or things like that, but it's basically the scope of the service worker and what it has access to. So if you put the service worker at the root of your application, then it's going to have access to everything as far as your application is concerned. If we were to put it inside of,

then it's going to have access to everything as far as your application is concerned. If we were to put it inside of, say, the icons folder inside of the public, so that would be slash icons, then the service worker would have access to everything inside of the icons folder and everything inside of the sub-directories of the icons folder. So it would just have a scope of the icons folder and everything in it and nothing else. So typically, you want your service worker to have access to everything about your application. So we're going to put it at the root. Eventually, we're going to take this outside of the public folder

Configuring Cache Names2:32

So we're going to put it at the root. Eventually, we're going to take this outside of the public folder and use Vite and things like that, but for right now, public is going to be fine. I'm going to create a couple of constants. The first is going to be the cache name, because when it comes to caches, we have several different caches that we can use and they are all based on keys. You can think of it somewhat like local storage, session storage, things like that,

You can think of it somewhat like local storage, session storage, things like that, but it's actually a cache storage object, so that we have different keys and we can store things inside of those different caches. So I'm going to use fieldlogger-v1, the idea being that we can version our caches based upon the name. This means though that if we want to actually version our caches, that we have to delete all of the other caches that are not our cache name, but that's something that we will do here in a moment. So we have our cache name.

but that's something that we will do here in a moment. So we have our cache name. The second thing that I want is the URLs that I want to always cache, and this can, well, it's of course going to vary based upon your applications. For this application for right now, I want to cache the root. I also want to cache offline. Now, we don't have that route yet, but we will. But the idea is that these are URLs that I want always available if my application is

Now, we don't have that route yet, but we will. But the idea is that these are URLs that I want always available if my application is offline so that I can provide that to whoever is using the application. So this is, of course, going to be different for every application. But typically, you want an offline page and you always want to cache that, so that you can always say, hey, you're offline or we think you're offline. So with that out of the way, the very first thing that we need to be aware of is when this service worker is installed.

Handling Install Event4:32

So with that out of the way, the very first thing that we need to be aware of is when this service worker is installed. When it is installed, the install event is going to fire. Now, notice I'm using self here. This is how we refer to the global object as far as the service worker is itself. So we use self. Inside of this install event listener, I want to essentially pre-cache the things that I want to pre-cache. So I could do that with caches,

I want to essentially pre-cache the things that I want to pre-cache. So I could do that with caches, which is that cache storage object, and I want to open the cache that we are currently working with. Now, this is going to return a promise because, well, everything is asynchronous here. So we need to think in terms of asynchronous JavaScript and using promises, so that whenever we open our cache, then we can work with that cache, and we are going to add all of the URLs that we want to cache,

then we can work with that cache, and we are going to add all of the URLs that we want to cache, which are our pre-cache URLs. But ideally, we want to wait for all of these things to be cached. So we are going to use the waitAll method, so that it is going to wait until all of these URLs are cached. Now, in our case, that's not going to be very long because, well, it's just not going to be very long. However, as your applications grow, as your service worker grows,

However, as your applications grow, as your service worker grows, you might want to not wait for development purposes. In which case, you can say skip waiting, and that will speed things on along. In production, you don't want to do that. But for development, that could be very useful to save you some time. So that is going to be our install. All we are wanting to do here is take the things that we want to pre-cache and cache them, so that we have them available.

All we are wanting to do here is take the things that we want to pre-cache and cache them, so that we have them available. Now, the install event is, of course, going to fire when it's installed. But whenever the service worker changes, the browser has to reinstall the service worker. So every time it's installed, so that means every version change is going to cause it to be reinstalled, which means that this event listener is going to install. Okay, so after we install, the next event that we are concerned with is the activate event.

Activating and Cleaning Caches7:04

Okay, so after we install, the next event that we are concerned with is the activate event. So at this point in time, the service worker is installed. Everything is pre-cached that we want pre-cached. Now, there's other things that we might want to do to initialize or to activate our service worker. In which case, in my mind, I want to clear out any cache that is not our field logger V1. So inside of activate, I'm going to essentially iterate over all of the available caches and delete them all that is not our current cache.

So inside of activate, I'm going to essentially iterate over all of the available caches and delete them all that is not our current cache. So once again, we will have our event object. And the first thing that we want to do is essentially get all of the names of our caches. And we can do that using our caches object. We have a method called keys, which is going to return all of our caches in. But we can't use await here, can we? So instead, we essentially want to do the same thing that we did up here for install. We want the service worker to wait until all of the caches are deleted.

So instead, we essentially want to do the same thing that we did up here for install. We want the service worker to wait until all of the caches are deleted. But we don't have wait all here because we are going to have just one promise. So we will wait until then we will have our async function that we will then need to execute. And that will give us the ability to await here, okay. So we are going to get the names of our caches so that then we can open up or no, we don't want to open. What we want to do is take the names and we want to filter out the names that are not our cache name.

What we want to do is take the names and we want to filter out the names that are not our cache name. So that's going to give us an array of the names that are not our cache name. So that then we can map over those. And if you type the wrong keystroke, things just appear there. So we are filtering out the names of their cache name that we're going to map over those filtered names so that we can delete that given cache. But this is going to essentially return multiple promises. So what we want to do is promise all so that we will run all of these promises.

So what we want to do is promise all so that we will run all of these promises. And our activate event listener is going to wait for that to be done. And for the most part, that's it. But the service worker isn't going to be available for any of the open tabs. Well, I take that back, that's not right. Let me rephrase it like this. If we have multiple tabs already open for our application, this service worker is going to activate but it's not going to activate for those open tabs.

this service worker is going to activate but it's not going to activate for those open tabs. We would have to reload those tabs in order for the service worker to start working for those tabs. Unless if we do this, we take all of the clients and we claim them. So this is going to tell the browser, hey, take all of the open tabs and activate the service worker for those. We're gonna claim them and make the service worker available for them so that they don't have to reload in order to have the service worker. Or the service, you get what I'm trying to say, I hope.

Implementing Offline Fetch10:30

them so that they don't have to reload in order to have the service worker. Or the service, you get what I'm trying to say, I hope. Okay, so the service worker is installed. It's activated and it's claiming all of the open tabs. So that then comes the fun part, the thing that we need to do in order to make all of this work. Which means we want to listen for a new event called fetch. This is going to fire when a request is made. Any request for any resource within the scope of the service worker, this event is going to fire, which means we can listen for that event.

Any request for any resource within the scope of the service worker, this event is going to fire, which means we can listen for that event. And the first thing I want to do is get the request that is given to us from the event object. Because if you think about this, we essentially want to cache almost everything. But we only want to cache a get request. Because if a post request is made, okay, I say that we are caching requests. We are caching the responses to those requests, okay? So we could cache the response of a post request. But that's not really ideal because that response is specific for

So we could cache the response of a post request. But that's not really ideal because that response is specific for that particular post request. So if it's not a get request, then there's really no sense in caching it. Because what would it be, a post request, a put, a patch? Those are all things that are going to change things on the server. The responses are specific to those requests, so we don't necessarily want to cache those. So instead, what we're going to do is check, if the method is not a get request, then we're just going to return, because we don't want to cache

So instead, what we're going to do is check, if the method is not a get request, then we're just going to return, because we don't want to cache the response of that request if it's not a get request. So then, if we are only concerned with get requests, we essentially then want to make sure that the user's device, the user's browser, can actually make the request that they are requesting. Okay, did I mention that the Service Worker is basically a programmable proxy that sits between our application and the network? So basically, what we want to do is take a network that we want to take a network first approach.

So basically, what we want to do is take a network that we want to take a network first approach. So a user is going to be on their device and they're going to try to make a request. That request might succeed, in which case, everything's fine. It might fail, in which case, it's probably a network issue. So this is going to give us the opportunity to actually check, is this request going to succeed? If so, then great, everything's fine. We actually cache the response so that we can provide that again. Or did the request fail?

We actually cache the response so that we can provide that again. Or did the request fail? In which case, that gives us the opportunity to say, hey, we think you're offline, so we're going to show you that we think you're offline. That's basically what we want to do here inside of this FetchEventListener, which means that we essentially want to hijack the response. And we want to provide our own, which we can do with the respondWith method. This is what a service worker does. I say hijack, and that sounds bad, but that is essentially what we are going to do. And it's going to look like this.

I say hijack, and that sounds bad, but that is essentially what we are going to do. And it's going to look like this. So we want to respond with a callback function. It's going to be asynchronous. And the first thing that we want to do is make sure that everything is going to work the way that we think that it's going to work. We want to take a network-first approach. If the network works, then great, everything's fine. So we are going to get the response of the request. So we're going to call fetch, we're going to pass in request.

So we are going to get the response of the request. So we're going to call fetch, we're going to pass in request. And if that succeeds, then we are going to open up our cache so that we can store the response in our cache. We do that by calling the put method. You can think of this kind of like a key value. So the key in this case is going to be the request. And then we want to provide the response. But response here, yes, this is a response, but it's a stream. So what we want to do then is copy it.

But response here, yes, this is a response, but it's a stream. So what we want to do then is copy it. So that we essentially replay the stream so that we can store it in our cache. And then we return the response. However, we need to wrap this in a try and catch, don't we? We do. All right, so we are going to try to fetch the request. If it succeeds, then we are going to cache that and we are going to return the response. So we have essentially hijacked that request.

we are going to return the response. So we have essentially hijacked that request. So this means if we wanted to, we could respond with whatever we wanted. Of course, that kind of defeats the purpose of having a service worker. So we will just respond with our normal response. However, Cache. If, for some reason, we fail to fetch this, and it's not a 404 or 500. It's because there was a network issue. Well then, the first thing that we want to do is see if we have something that's already cached for this particular request.

Well then, the first thing that we want to do is see if we have something that's already cached for this particular request. In which case, we'll say caches match and this request. And if it is cached, then we'll just return the cached. That way it's a network first. If the network is fine, then we return the response. If it's not, and if we've cached it, then we return the cache. Otherwise, we don't know what to return. So then, we want to check. Did the user try to navigate to whatever it is that they requested?

So then, we want to check. Did the user try to navigate to whatever it is that they requested? So did they input something into the address bar and click or tap Enter? Did they click or tap a link that took them to whatever it is that we wanted here? Or did they refresh the page? All of those things are considered navigation. So we're basically saying, if the request is a top level page navigation and the network and the cache both failed, then we want to get the offline from our cache. So therefore, we show the offline page. But we do need the ultimate fallback.

So therefore, we show the offline page. But we do need the ultimate fallback. If for whatever reason, the request mode wasn't navigate and the network and the cache failed, then we will return a new response that says offline for the body. And the status will be 503, and that should be enough there. So the next thing we need is this offline endpoint. So let's open up our route file. And I believe we could just do this to where we'll have our view. Offline is the URL.

And I believe we could just do this to where we'll have our view. Offline is the URL. We want the offline view. And let's give this a name of offline. Of course, need that view. So let's go to the Resources folder, Views. And let's create a new file, offline.blade.php. And I'm gonna just paste that in, so that then we just need to register our service workers. Not enough to just write this, we also have to register it.

that then we just need to register our service workers. Not enough to just write this, we also have to register it. And we can do that, where do we wanna do that? Well, the answer to that is pretty simple. We want to register our service worker practically on every page that we want our service worker to run on, which is gonna be everything. So that means the layout makes the most sense. And we typically want to do this right before the closing body tag. So we will have a script element, and we will just register that service worker.

So we will have a script element, and we will just register that service worker. We'll do so with the Windows load event. So let's add that event listener. And we are going to use navigator.serviceWorker, which has a register method. We specify the name of the file of the service worker. And really that could be enough, but we can provide options. In which case, we could set the scope, if we wanted to do that here. Otherwise, the scope would just be inferred based upon the location of the file.

In which case, we could set the scope, if we wanted to do that here. Otherwise, the scope would just be inferred based upon the location of the file. I'm gonna be explicit, and I'm gonna say, use the root as the scope. And that's gonna be it. So in the browser, let's pull up the developer tools, and we have an error. Wait all, of course, we don't have wait all. That's a different language. So let's go back, and we won't wait until instead of wait all. Sorry about that. So we'll go back, and let's clear that, let's do a hard refresh.

Sorry about that. So we'll go back, and let's clear that, let's do a hard refresh. Everything should be fine. Now if we go to the application tab, we're gonna see things about our application. Now of course there's manifest, but then there's service workers. Now right here is status, you're gonna see number 12 for me. That's because I don't know how to reset this, so you can hit stop. You can hit unregister, and that completely unregisters your service worker. So right now, I just removed it.

You can hit unregister, and that completely unregisters your service worker. So right now, I just removed it. But if you refresh it, it's gonna load it again, because it's part of our layout page. And we can see that it incremented here. There's also this option to update on reload. So every time you refresh the page, it's going to reinstall that service worker, which that can be useful for developer purposes. But if we take a look here, what do we have? We'll talk about offline here in a moment.

But if we take a look here, what do we have? We'll talk about offline here in a moment. But if we take a look, we can see that we could send push notifications if we wanted. We don't have that really working right now, so we'll talk about that later. Sync and periodic sync, but then we can see all registrations for this service worker. It's gonna give us just information about this service worker, and yeah, that is that. Now, if we look down, let's see, where's cache? I thought there was something about cache here.

Now, if we look down, let's see, where's cache? I thought there was something about cache here. But if we look down here, well, if we look at storage, that's where we'll see cache. So we can see that there's a usage. We are using practically 32 meg of storage, and we have a max of 80, that's a lot. So we have a lot of storage. We can see what that breakdown is. The cache storage is, of course, the majority here that we have. Then there's service workers.

The cache storage is, of course, the majority here that we have. Then there's service workers. But if we wanted to see what that is, we can go down here to cache storage. And we can take a look and see what has been cached. It's a lot that's been cached. But of course, nothing is really useful for us right now until we sign in. So we had tim.example.com, password. So we can, of course, go to any one of these pages. Everything is gonna work fine because these are pages that we can get to without any issue because we are on the network.

Everything is gonna work fine because these are pages that we can get to without any issue because we are on the network. But of course, we want to test without any network communication. So we can go back to service workers here, and we can click on offline. That's going to simulate that we are offline. So what do we do? We viewed this one here, this first one. So we can go back to view, and we can still see that information. But we are pulling it from cache, or at least we're supposed to be pulling it from cache.

But we are pulling it from cache, or at least we're supposed to be pulling it from cache. If we take a look at the edit, same thing. Because we have already gone to this page, and it is already cached. But if we go to something that we haven't gone to, like this one here, if we click on view, we're offline. We can't reach the network right now. Please try again when you're back online. So we now see that we have the ability to go offline. As long as we are online,

So we now see that we have the ability to go offline. As long as we are online, it is going to cache those requests if they are GET requests. So I just took us back online. What was it? Was it this one that we went to, this Spinka? So if we view that, and we go back, and we go offline, and if we try to view that again, it's cached now. So we pull that information from the cache. But once again, if we go to any others, we're going to see that we are offline. So we now have a service worker that is working on our behalf to cache

But once again, if we go to any others, we're going to see that we are offline. So we now have a service worker that is working on our behalf to cache our stuff, so that if we do inadvertently go offline because of poor connections or anything like that, then our application is going to work. In the next episode, we are going to cache static assets.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟