Understanding the ServiceWorker

A ServiceWorker is a proxy that sits between our web applications and the server. It catches requests that are made and checks if there is a pattern that matches it. If a pattern matches it, then it will run the code that fits that pattern. Writing code for a ServiceWorker is a bit different than it is for SharedWorker and DedicatedWorker, which we looked at previously. Initially, we set it up in some code and it downloads itself. We have various events that tell us the stage that the worker is in. These run in the following order:

  1. Download: The ServiceWorker is downloading itself for the domain or subdomain.
  2. Install: The ServiceWorker is attaching itself to the domain or subdomain where it is hosted.
  3. Activate: The ServiceWorker is fully attached and is loaded up to intercept requests.

The install event is especially important. This is where we can listen for a ServiceWorker that is updated. Say that we want to push new code out for our ServiceWorker. If a user is still on a page when we decide to push that code out to the server, they will still have the old worker. There are ways to kill off this old worker and force them to update (as we will see in a bit), but it will still utilize the old cache.

On top of this, if we are utilizing a cache to store the resources that are being requested, they will be stored in the old cache. If we were to update these resources, then we want to make sure that we dump the previous cache and start with a new one. We will look at an example of this later, but it is good to know this upfront.

Finally, service workers will update themselves every 24 hours, so if we don't force the user to update the ServiceWorker, they will get this new copy on that 24-hour mark. These are all ideas to keep in mind as we go through the examples in this chapter. We will remind you of these when we write them out.

Let's start off with a very basic example. Follow these steps:

  1. First, we need a static server so that we can work with service workers. To do this, run npm install serve and add the following code to the app.js file:
const handler = require('serve-handler');
const http = require('http');
const server = http.createServer((req, res) => {
return handler(req, res, {
public : 'source'
});
});
server.listen(3000, () => {
console.log('listening at 3000');
});
  1. Now, we can serve all of our content from the source directory. Create a basic HTML page and have it load in a ServiceWorker called BaseServiceWorker.js:
<!DOCTYPE html>
<html>
<head>
<!-- get some resources -->
</head>
<body>
<script type="text/javascript">
navigator.serviceWorker.register('./BaseServiceWorker.js',
{ scope : '/'})
.then((reg) => {
console.log('successfully registered worker');
}).catch((err) => {
console.error('there seems to be an issue!');
})
</script>
</body>
</html>
  1. Create a basic ServiceWorker that will log to our console whenever a request is made:
self.addEventListener('install', (event) => {
console.log('we are installed!');
});
self.addEventListener('fetch', (event) => {
console.log('a request was made!');
fetch(event.request);
});

We should see two messages appear in our console. One should be static, stating that we have installed everything correctly, while the other will state that we have successfully registered a worker! Now, let's add a CSS file to our HTML and service it.

  1. Call our new CSS file main.css and add the following CSS to it:
*, :root {
margin : 0;
padding : 0;
font-size : 12px;
}
  1. Add this CSS file to the top of our HTML page.

With this, reload the page and see what it states in the console. Notice how it doesn't state that we have successfully made a request. If we keep hitting the reload button, we may see the message appear before the page reloads. If we want to see this message, we can head to the following link inside of Chrome and inspect the ServiceWorker that's there: chrome://serviceworker-internals.

We may see other service workers being loaded in. Quite a few sites do this and it is a technique for caching certain pieces of a web page. We will look at this in more detail soon. This is why the first load can be quite a pain for some applications and why they seem to load up a lot faster afterward.

The top of the page should show an option for starting the dev tools when we start the ServiceWorker. Go ahead and check this option. Then, stop/start the worker. Now, a console should open that allows us to debug our ServiceWorker:

While this is great for debugging, if we take a look at the page where we initiate this behavior, we will see a little window that states something similar to the following:

Console: {"lineNumber":2,"message":"we are installed!","message_level":1,"sourceIdentifier":3,"sourceURL":"http://localhost:3000/BaseServiceWorker.js"}

It is getting the CSS file every single time we reload the page! If we reload it a few more times, we should have more of these messages. This is interesting, but we can definitely do a bit better than this. Let's go ahead and cache our main.css file. Add the following to our BaseServiceWorker.js file:

self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll([
'./main.css'
]);
}).then(() => {
console.log('we are ready!');
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
)
});

With this, we have introduced a cache. This cache will fetch various resources for us. Along with this cache, we have introduced the waitUntil method of the event. This allows us to hold up the initialization of the ServiceWorker until we are done fetching all of the data we want from the server. Inside of our fetch handler, we are now checking to see if we have the resource in our cache. If we do, we will serve that file up; otherwise, we will just make the fetch request on the page's behalf.

Now, if we load the page, we will notice that we just have the we are ready message. Even though we have new code, the page was cached by Chrome, so it hasn't let go of our old service worker. To force the new service worker to be added, we can go into our developer console and head to the Application tab. Then, we can go to the left panel and head over to the ServiceWorker section. There should be a timeline stating that there is a ServiceWorker waiting to be activated. If we click the text next to it that says skipWaiting, we can activate the new code.

Go ahead and click on this option. It won't look like anything has happened, but if we head back to the chrome://serviceworker-internals page, we will see that there is a single message. If we keep reloading the page, we will see that we just have the one message. This means that we have loaded in our new code!

Another way to check that we have successfully cached our main.css file is to throttle the download speed of our application (especially since we are hosting it locally). Head back to the developer tools and click the Network tab. There should be a dropdown of network speeds near the Disable cache option. Currently, it should state that we are online. Go ahead and turn this to offline:

Well, we just lost our page! Inside of BaseServiceWorker.js, we should add the following:

caches.open('v1').then((cache) => {
return cache.addAll([
'./main.css',
'/'
]);
})

Now, we can turn our application online again and have this new ServiceWorker add itself to the page. Once it's been added, go ahead and turn our application offline. Now, the page works offline! We will explore this idea in more detail later, but this gives us a nice preview of this capability.

With this simple look at the ServiceWorker and caching mechanism, let's turn our attention to caching pages and adding some templating capabilities inside of our ServiceWorker.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.186.164