You are on page 1of 9

371

Adeyinka Adegbenro Follow


Adeyinka is a software developer, who is constantly trying to learn and apply.
Mar 21 · 9 min read

A Simple Guide to Taking a Web Page


O ine, using Service Workers

A service worker is a script that runs in the background when your


application/website is running. It acts as an intermediary between the
browser and your app.

It has the ability to intercept network requests, modify them and redirect
them; it is quite powerful. The service worker’s main function is to serve a
cached/stored version of your application when the network is down. This
makes them suitable for making your website work o ine.

A very simpli ed explanation as to how service workers work, is this,

1. When your site loads in the browser, the service worker nds all the les
you speci cally tell it to store, downloads them and then stores them in a
space in the browser known as the cache. You can store anything from
images, videos, html les, icons etc. These les should be les needed by
your website or web page to function.
But there’s a catch, if any one of the les you speci ed fails to download,
the installation process fails, then your service worker won’t be activated.
On the other hand, if all the les are successfully downloaded, the service
worker can then be activated. This phase is called the installation phase.

2. Then, when a visitor visits your web app for the rst time, the service-
worker from your site goes through the installation phase on their
computer. On subsequent visits to your website, if same visitor loses
internet connection, the service worker picks up on this and reaches into
the browser storage for the les previously downloaded in the installation
phase and displays your website. This is called the fetching phase

This API is quite exciting and powerful. If you feel like you could use this and
you are not a developer, it is best to consult one and discuss the
merits/demerits and how it could work for your web application. On the
other hand, if you are a developer, I have some code samples we can go
through as to how to go about implementing the o ine experience.

How to Implement a Service Worker


The rst step to implementing the o ine experience is to register the service
worker. But before we can do this, in order for the service worker to work
locally i.e not on a production server, we need to create a local development
server for the application. Which means you can’t just visit “index.html” in
your browser and expect the service worker to work

We could use the python framework ask or the Javascript framework,


node.js to create a quick server. I choose to use ask. To follow, you need to
download python for your operating system, and then install ask by doing

pip install flask

You also need to clone the code repository I’ll be demonstrating with, by doing

git clone
https://github.com/AdeyinkaAdegbenro/Javascript_Calculator.git

Currently, our directory structure looks somewhat like this;

JavaScript_Calculator

→index.html

→readme.MD

→style.css

→script.js

We are going to change this.

• Create a le named server.py and type in the code below. Below, we


create two routes. The rst /index , which makes sure that when you
navigate to /index in the browser, it renders index.html, the second
/sw.js , makes sure that when your code calls /sw.js , it serves the
content of sw.js from the static folder

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/index')
def home():
return render_template('index.html')

@app.route('/sw.js', methods=['GET'])
def sw():
return app.send_static_file('sw.js')

app.run(debug=True)

• Create a folder named templates . Move index.html from the root folder
to the templates folder. We are moving index.html because ask serves
its html les from the templates folder by default.

• Create a folder named static . Move both script.js and style.css to


the static folder. We are also moving these two les because ask serves its
static les from the static folder.

• Since we have moved the positions of our static les, we have to update
their paths in the script tags in index.html . Open templates/index.html,
and on lines 3 and 12 change style.css to /static/style.css and
script.js to /static/script.js respectively. At the end of the day we
have something like this:
our new templates/index.html

Our directory structure should now look like below;

JavaScript_Calculator

→server.py

→readme.MD

→templates

→→index.html

→static

→ →style.css

→ →script.js

N.B → → represents les in a folder while bold letter represent folders

Now run python server.py or python3 server.py in your console as the


case maybe, then visit http://localhost:5000/index in your browser.

We are now ready for the next step.

Registering the Service Worker

Create a le named sw.js and then place it in the static directory. Then go to
static/script.js and enter the following at the bottom

if ('serviceWorker' in navigator) {
// we are checking here to see if the browser supports the
service worker api
window.addEventListener('load', function() {

navigator.serviceWorker.register('../sw.js').then(function(registr
ation) {
// Registration was successful
console.log('Service Worker registration was successful with
scope: ', registration.scope);
}, function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
});
}

The line
navigator.serviceWorker.register('../sw.js').then(function(registrati

on...

is the main code that does the registration of our service worker script.

The register method takes the url of our sw.js script. Remember, in our
Flask le server.py , we created a route that tells Flask to nd the le for url
/sw.js in /static/sw.js ; we have to tell our script.js le how to nd our
sw.js le. We do this by pre xing the url /sw.js with a .. , which is
basically telling the browser to change the directory a step back (from the
static folder to the root folder) and call sw.js . Now visit http://localhost:5000
in your browser and open your console. You should see this:

Service worker successfully registered

Also, chrome has made it very easy to debug service workers by providing the
application tab in the console. Visit the console by doing ctrl shift i . If
you visit the application tab, you see this:

The application tab

This comes in handy while trying to monitor/debug our service worker script.
If you click the little blue sw.js in your browser, it is going to take you to the
empty source of our sw.js le. It is empty because we have not added any code
to it.

We are going to type the following in our sw.js le:

var CACHE_NAME = 'offline-calculator';


var urlsToCache = [
'/',
'/index',
'/static/style.css',
'/static/script.js'

self.addEventListener('install', function(event) {
// install files needed offline
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})

});

The code above handles the installation phase of the service worker script.
What we did is this, we are asking the script to install the urls needed for the
calculator to work. They include ‘/’, ‘/static/style.css’,

‘/static/script.js’. Urls ‘/’ and ‘/index’ are the routes that serve our
index.html le. You can con rm this by checking server.py . So ultimately,
all we are doing is saving les returned by each route/path in the browser
cache. o ine-calculator is the name of the cache where we are asking the
script to store our les in the browser. So think of it as storing les the browser
would normally request from the server in the browser. This way, when
there’s a network issue, the browser can serve your web app’s les from its
own storage without the internet. Sort of like downloading movies to your sd
card so you don’t have to stream them every time.

Make sure your server is running using python server.py. Then navigate to
http://localhost:5000/. Also, make sure your console is open. In your console,
visit the Application tab. You should see the o ine-calculator cache in the
cache storage section:

The Application Tab

When you click the o ine-calculator line, you should see the les that have
been cached:

Our site cache

Now that we have con rmed that our les have been cached in the browser,
it’s time to go o ine. Oh wait, we can’t. Reason — if we go o ine now, the
script does not know how to retrieve our les to show the user. You have to
teach it how. That’s where the fetch handler comes in.

Let’s implement the fetch handler, shall we?

self.addEventListener('fetch', function(event) {
// every request from our site, passes through the fetch handler
// I have proof
console.log('I am a request with url:',
event.request.clone().url)
event.respondWith(
// check all the caches in the browser and find
// out whether our request is in any of them
caches.match(event.request)
.then(function(response) {
if (response) {
// if we are here, that means there's a match
//return the response stored in browser
return response;
}
// no match in cache, use the network instead
return fetch(event.request);
}
)

});

What we have done here is set a fetch event listener. The listener well, listens
for any form of web request and then checks if the request is stored in our
browser cache. If it is, the response is gotten from the le stored in the cache.
If however, the request was not found, then we just
do fetch(event.request) . Which is equivalent to how the browser will get
the request normally.

For a better understanding of how the fetch and cache API works, study
these resources, cache and fetch.

It is time to reload our page. Reload it once to update the script. And then,
shut down the ask server, and also put your computer in airplane mode.
Now after reloading the page again, I get this

We have our page loading o ine alright. Except our calculator does not seem
to be working. From my console, I can see the fetch event for

blablabla.com resulted in a network error response. It seems I forgot to


add jquery to the list of urls to save in the browser. Since JQuery is used
extensively in our calculator code, it won’t work without it. I’m going to go
ahead and add the Jquery cdn to the list urlstoCache in our code and save
the le.

var urlsToCache = [
'/',
'/static/style.css',
'/static/script.js',
'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.j
s'

Now we go back online and reload our page (don’t forget to start your server up
again), and then go o ine again (shut your server down too) . After reloading
my page, I get this

Tada!

Since we added the jquery url to our list of urls to cache, our calculator can
now work o ine. Also, the cache has been updated with the jquery url
Jquery in Cache storage

We now have a working calculator o ine. You can nd the before and after
code on github.

While this tutorial might look easy, this is not all there is to know about
service workers. There’s more, but I wanted to introduce you to the most fun
part rst, so you won’t get bored. Here are other topics and resources (in no
particular order) you should look into, if you want to dive deeper into service
workers and fully understand how they work

1. https://developers.google.com/web/fundamentals/primers/service-
workers/

2. serviceworke.rs — The service worker cookbook

3. The W3C Speci cations https://www.w3.org/TR/service-workers-1/

4. https://developer.mozilla.org/en-US/docs/Web/API/Cache

5. https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API

6. Promises — Used extensively in service workers


https://developers.google.com/web/fundamentals/primers/promises

7. Async Functions — Also used extensively in service workers


https://developers.google.com/web/fundamentals/primers/async-
functions

8. Google is also your best friend https://www.google.com.ng/search?


q=service+workers

Ciao.

JavaScript Python Flask Software Development Programming

One clap, two clap, three clap, forty?


By clapping more or less, you can signal to us which stories really stand out.

371 5

Adeyinka Follow FormPlus Blog Follow


Adegbenro Form+ helps you create
Adeyinka is a software easy to use forms, easily.
developer, who is
constantly trying to learn
and apply.

More from FormPlus Blog More from FormPlus Blog


O ine Forms now in Formplus! Macro In uence vs. Relevance,
Take a look at our Latest Features What’s Wrong with Your In uenc…
Marketing Campaigns?
Form+ Form+
6 min read 4 min read
Responses

Write a response…

Applause from Adeyinka Adegbenro (author)

Hafiz Adewuyi
Mar 29

We are going to type the following in our sw.js le:

I like that you use type instead of copy and paste. I’ve read from multiple
sources that a major part of learning when you’re following along with
already-written code is to type it out line-by-line.

Conversation between Ha z Adewuyi and Adeyinka Adegbenro.

Hafiz Adewuyi
Mar 29

self.addEventListener('fetch', function(event) { // every request from


our site, passes through the fetch handler // I have proof console.log('I
am a request with url:', event....

For clarity, it should be speci ed that this code should also be included in the
sw.js le (remember we also have script.js), just below the rst block of code.

6 1 response

Adeyinka Adegbenro
Mar 29

You have a point. I’ll update the article.

Conversation with Adeyinka Adegbenro.

Yunfan
Mar 23

interesting, will `cache` share the limitation with other browser side storage
system like sessionstorage?

1 response

Adeyinka Adegbenro
Mar 23

Unlike session storage, cache storage does not expire per session unless you
explicitly delete it. The only limitation with cache storage is that each browser
has a limit on the amount of cache storage an origin can use. If you exceed
that limit, the browser can delete your cache. There’s an api, StorageEstimate,
one can use it to check the available space for your origin.

Conversation with Adeyinka Adegbenro.

Hafiz Adewuyi
Mar 29 · 1 min read

Service worker successfully registered

When I rst loaded my website after including the service worker registration
code, I got the error: “Invalid MIME type: text/plain”.

I had to manually set the Content-Type header to ‘application/javascript’ in


my action:
@app.route(‘/sw.js’, methods=[‘GET’])

Read more…

1 response

Adeyinka Adegbenro
Mar 29

That’s weird. I’m glad you found a solution.

Conversation between Adeyinka Adegbenro and Ha z Adewuyi.

Hafiz Adewuyi
Mar 29

change the directory a step back (from the static folder to the root
folder) and call sw.js

Why does the browser need to take a step back when the sw.js le is in the
same folder as the script.js le?

1 response

Adeyinka Adegbenro
Mar 31

The reason I made the browser take a step back is because our server (Flask)
which handles browser requests recognizes the /sw.js route as a le in the
static folder. Remember in server.py, we created a route to serve sw.js.

1 response

Hafiz Adewuyi
Mar 31 · 1 min read

I see.

But I gured the navigation is not necessary. Since the


navigator.serviceWorker.register() method works with HTTP routes and
not the folder structure of your application.

I changed it like below in my own code and it still worked:

navigator.serviceWorker.register(‘/sw…

Read more…

3 1 response

Adeyinka Adegbenro
Apr 2

It never occurred to me to try that. Nice catch!

You might also like