BrowserWorker - service workers made easy
Tags: javascript, node, serviceworker
Published: 2019-06-15 14:39:36

---
title: BrowserWorker - service workers made easy
published: true
description: I am explaining how to use my library to set up a service worker easily.
tags: javascript, nodejs, service worker
---

Welcome everyone!

I am very happy to show you [BrowserWorker](https://github.com/khalyomede/browser-worker), my latest project. The goal of this library is to help you set up a Service Workers more easily than having to deal with a lot of verbose syntax or copy/paste to use a specific cache strategy.

At the moment I am writing this post, the library is in early development stage, and only usable through WebPack, Browserify or any other tool that transpiles your code for the browser. In future releases, you will be able to just use it from a CDN.

If you like the idea of this library, let's see how to use it!

![Let's go let's go! gif](https://media.giphy.com/media/4GXUa4U05Q0JAM972c/giphy.gif)

## Installing

In a fresh new folder, initialize a node project. For the rest of the topic, I will use `yarn`, but you can use any dependency manager you like.

```bash
yarn init --yes
```

_I use `--yes` to skip filling the configuration._

Then, we will install [`@khalyomede/browser-worker`]().

```bash
yarn add --dev @khalyomede/browser-worker
```

The rest of the tools I will install is to be able to create a browser-compatible code. If you already use a tool like WebPack or Rollup, it is fine to skip this and jump into the next section.

To continue, I will add `gulp`, `gulp-bro`, (browserify), `gulp-plumber` (to not terminate my build at the first error), `@babel/core`, `@babel/preset-env` (to transpile ES6 syntaxes), `@babel/register` (to be able to use ES6 in my `gulpfile.js`), `babelify` (to pass it to `gulp-bro`), and `browser-sync` (to reload our page when files have been changed and saved).

```bash
yarn add --dev gulp gulp-bro gulp-plumber @babel/core @babel/preset-env @babel/register babelify
```

Then, I will create a `gulpfile.babel.js` to use gulp recipes in order to produce a browser-compatible code.

```javascript
// your-app/gulpfile.babel.js

import { src, dest, watch, series } from "gulp";
import browserify from "gulp-bro";
import plumber from "gulp-plumber";
import browserSync from "browser-sync";

const browser = browserSync.create();

const js = () =>
  src("src/**/*.js")
    .pipe(plumber())
    .pipe(browserify({ transform: ["babelify"] }))
    .pipe(dest("dist"))
    .pipe(browser.stream());

const reload = done => {
  browser.reload();

  done();
};

const start = () => {
  browser.init({
    server: {
      baseDir: "dist"
    }
  });

  watch("src/**/*.js", series(js, reload));
};

export { start };
```

I need to update my `package.json` to be able to use a `start` command, which will call `gulp watch` and transpile my files when they change.

```javascript
...
"scripts": {
  "start": "gulp start"
}
...
```

I will also need a `.babelrc` file to set up my preset:

```javascript
{
  "presets": ["@babel/preset-env"]
}
```

We are good to go! You can run the start command now.

```bash
yarn start
```

You will see that your browser will open and the page will display a 404. This is totally fine and we will create the html file soon.

## Set up

In a first place, we will create the service worker itself, and then creating the script that will register it.

In the file `src/service-worker.js`, add this code.

```javascript
// your-app/src/service-worker.js
import { BrowserWorker } from "@khalyomede/browser-worker";

BrowserWorker.enableDebug();
```

On save, you should see that a new file `dist/service-worker.js` have been generated. Do not dare to see it, young fool! It has been made from dark magic and young internship python developpers blood.

This code above will be run by the service worker, but it cannot run until we register it.

In another file, `register-service-worker.js`, add this code.

```javascript
// your-app/src/js/register-service-worker.js
import { BrowserWorker } from "@khalyomede/browser-worker";

BrowserWorker.enableDebug();

BrowserWorker.setServiceWorkerPath("/service-worker.js").registerServiceWorker();
```

Again, saving this file should create its dist counterpart file. 

This code is responsible for registering your service worker on your page.

Finally, to see the result of this setup, we will create an HTML file that will reference our `register-service-worker.js` file. Create it **on the dist** file (it is dirty, but fine for this showcase).

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <script type="text/javascript" src="/js/register-service-worker.js" async></script>
  </head>
  <body>
    <h1>Hello from the index HTML</h1>
  </body>
</html>
```

Now you can come back to your browser, and reload the page `http://localhost:3000` to see the page.

Open the developper console, and you should see the following message:

```
[BrowserWorker][15:51:43.598] service worker registered (scope: http://localhost:3000/).
```

If you reload your page, you will see that your service worker is now online.

![Image showing that the service worker is ready on the application panel of chrome](https://thepracticaldev.s3.amazonaws.com/i/rbtt3sw62c76lahei87v.png)

Since your are on the `Application` panel (on Chrome), try to check the `Offline` option and reload your page... Yes, it totally screwed your app and a wild dinosaur appears!

![But why? meme gif](https://media.giphy.com/media/s239QJIh56sRW/giphy.gif)

## Setting up a cache strategy

Since you did not tell your service worker to process requests, nothing happens. Let's fix this by using a network first strategy on our home page.

Update your `service-worker.js` file like this.

```javascript
import { BrowserWorker, CacheStrategy } from "@khalyomede/browser-worker";

BrowserWorker.enableDebug();

BrowserWorker.setCacheStrategy(CacheStrategy.NETWORK_FIRST)
  .setCacheName("network-first-v1")
  .addRoute("/");

BrowserWorker.listenRequests();
```

Now, after saving your file, you should see something like this in console.

```
[BrowserWorker][16:05:26.652] service worker registered (scope: http://localhost:3000/).
[BrowserWorker][16:05:28.457] waiting for others instances before installing (if you want to skip waiting, use BrowserWorker.disableWaitingOtherInstances())
```

And in your Application panel, you see that your new service worker is waiting for the other to terminate to install ("Waiting to activate"). To fix this, add this line right after enabling the debug mode.

```javascript
import { BrowserWorker, CacheStrategy } from "@khalyomede/browser-worker";

BrowserWorker.enableDebug();
BrowserWorker.disableWaitingOtherInstances(); // this one

BrowserWorker.setCacheStrategy(CacheStrategy.NETWORK_FIRST)
  .setCacheName("network-first-v1")
  .addRoute("/");

BrowserWorker.listenRequests();
```

Now you should see better results in your console:

```
[BrowserWorker][16:08:38.669] service worker registered (scope: http://localhost:3000/).
[BrowserWorker][16:08:40.637] skipped waiting for other instances to finish.
[BrowserWorker][16:08:41.653] cleaned old caches.
```

And in your Application panel, no more service worker waiting to install.

![Service worker is not waiting the previous anymore and is installed correctly, viewing it in the application panel of the chrome console developper](https://thepracticaldev.s3.amazonaws.com/i/f0xd8i2eip9hfel5am1e.png)

Reload your browser and look at the network panel.

![Home page have been handled by the service worker](https://thepracticaldev.s3.amazonaws.com/i/lfuehezeg4hmpzlhhpbw.png)

Your home page seems to have been handled by your service worker, congrats! Since you asked your service worker to fetch it from the network first, it has also nicely put your response in the cache.

Go on the Application panel again, and check for the "Cache" section.

![Cache storage contains the home page as well](https://thepracticaldev.s3.amazonaws.com/i/1d04vdfgy4rcw7tcv5qv.png)

Do you know what it means? Oh yes you know what it means!

![Cat wiggling with Shaqil](https://media.giphy.com/media/H0EBDM4Vk6880/giphy.gif)

Check the "Offline" checkbox again and reload the page: offline web app!

## Conclusion

With this first introduction on how to use BrowserWorker, we have successfuly used a cache strategy to respond to both online and offline network condition.

Service workers are becoming mature and that is why I wanted to create this library to help you use it in your app.

Feel free to create issues if you noticed some. Some parts of this library remain untested, so be careful in the jungle.

Last but not least, make sure you read the `Advice` section of the README, it contains precious information even if you want to try Service Worker on your own without this library. 

If you want to use more in this library, like to be able to cache a resource ahead of time to recreate "read offline later" features, and so on, make sure to check the README on the documentation : [https://www.npmjs.com/package/@khalyomede/browser-worker](https://www.npmjs.com/package/@khalyomede/browser-worker)

I hope you had fun like I had, learnt things, and maybe want to try this technology for your app. 

Happy caching!

![I have to go now meme gif](https://media.giphy.com/media/3og0IzFCXnbb5uURH2/giphy.gif)