Building an Angular PWA: Angular Service Worker or Workbox? | Maxim Salnikov | #AngularConnect 2018

Building an Angular PWA: Angular Service Worker or Workbox? | Maxim Salnikov | #AngularConnect 2018


Good evening, dear developers. Let’s help
our little offline dinosaur, because, they’re so tired to show up on many pages with “server
not found” message when we don’t have an internet connection, maybe they would like to go to
relax with friends, go out, so let’s free our pixel friend from this job, because we
can provide offline experience for our Angular applications, but we only have to help to
dino to decide which option to go for. It’s a luxury problem because both methods are
really nice, and talking more generally, we will talk today about how do we create progressive
web apps using Angular, using this or that approach? My name is Maxim Salnikov. I dedicate
pretty much all my spare time organising something, or speaking on some events, mostly about Angular
or PWA, or them both, like, today. I have this picture for a reason. Stay tuned. Follow
my Twitter. I really kindly ask to you follow this, because our today’s session will contain
some code and lots of beautiful limping. I will post the link to these – links. … what
is PWA? In very simple words, let’s take a definition from the Moz://a developer network.
These are web applications which use some nice modern APIs from the modern browsers.
Why? To deliver the best possible user experience, to delight our clients by their features that
were never available on the web before. If we mentioned cross-platform, let’s list the
current situation. By running it cross-platform, I mean running it as a first-class citizen.
All the major browsers are there to some extent at least, the same on mobile forms on Android,
it will take some time for you to understand is this a native JavaScript written in Kotlin
or JavaScript in – it works on iOS with some bugs in the background but still the basics
are there. On desktops, it’s also really nice, obviously, it’s hard to imagine better native
place for PWA than Chrome OS which is like browser-based operating system in general.
On windows, you can install these apps via Microsoft store or from Chrome on Linux using
Chrome. We are soon the same support will be added in Mac, desktop systems, so this
will be the real native application, at least platforms will think about this. This level
of support gives me permission to call this year 2018 as the year of PWA. Briefly about
the advantage we bring to our user by using this these interesting technologies. First,
and maybe it’s something that comes up first to our mind when we hear about PWA, yes, this
is about networking magic, including full offline support for the application. If you
have the privilege – this is a privilege – to be online, we can reach out to our users by
sending notifications, even if the web application is not running, not planning at all, right?
But let’s don’t overuse this powerful possibility. And many other things powered by service worker
API, so the sky is the limit. This is basically whole new programmable layer between our app
and everything else. And we wrap our files in HTML and the CSS into app, into what we
can call app-for-this or that system, following the system JSON file following the web app
manifest specification. What about Angular? Of course, as any modern framework, Angular
embraces web apps, and progressive web apps. There are interesting options for us. How
do we do this? Mainly, we are speaking about a service worker, when we are talking about
development of some apps, right? We can do everything by our hands. So service worker,
script file. Next, we can use built-in functionality, native, Native in context of Angular, of course,
or any kind of sort libraries. We have also really nice options here. So, let’s start.
Let’s first understand what will it take to create minimum viable PWA, like PWA and VP?
And I tried a different approach how to build this slide deck, because we are going to go
through some features of two different approaches, and I ended up with what I call colour-coding.
So all on the blue background will be dedicated to NGSW, or NG service worker, and everything
on brown, Workbox. Remember this. I will test you in a few moments! Before this, let’s understand
what is PWA and. JSON file to wrap everything to application. App shell, this is special
architecture which is responsible for having everything running and working offline. And
two more points, so, this is like my accumulated checklist that I accumulated from other checklist
I found on the web, but the last to are two points, let’s say that we create our apps
like this by default, right? So it’s not directly related to PWA and service worker, this is
why we focus on application shell. Let’s understand, what will it take from us if we want to provide
this architecture? First, application shell is about UI of our application. So we have
to understand which files do we want to take and generate the list of this file, plus calculate
some hash sums, in a few moments, why do we need this? Then, on the application start,
our service worker is taking control, and it’s populating the cache storage. Don’t mess
this up with HTTP storage. These are completely different things. On the next loads, instead
of going network, service worker takes resources, and sources this from this storage. So this
is the basics of how offline works, how any service worker intended to work, but most
likely, we don’t want to always – the initial version of the app which was cached on the
very first start, right? This is why, on the same time, during service worker work, it
should go and check if something was updated and hash is helping us with doing that, and
on the next load, we can sort this updated version. So I have a small comment here. What
can we do to improve user experience on that step? To show the message, that the application
was updated? We will stop more details on this mechanism in a few minutes but let’s
group what we listed here, two or three categories. First, everything has to be on build. Second,
basically, this is what service worker should do for us, and, of course, we don’t want to
code it manually. It will take some time, and some skills. And, sort, this is not like
must-have in nvp PWA, but we’re thinking about better user experience, so it’s really good
to have like this. Now, time for me to test you. What do we show on the blue background?
Right. Angular service worker or NGSW. How do we start? What is it all about? It’s all
about automation on all the steps of the flow. Scaffolding. We use schematics. We use the
power of CLI to generate the services we need. NG service worker, itself, angular service
worker. Okay, scaffold. How do we start? Schematics. One line of code and we have all the boring
operations done for us. We add the code, we generate some files, and we enable build support.
What do we mean by build support? When we run production build, CLI, with this support
enabled, generates special files for Angular service worker. The settings file, but in
terms of service worker, this is a manifest, but again, please don’t mess up this manifest
and web app manifest. The same kind of name but totally different goals, right? You will
find this under the name of ngsw.json. It copies Angular service worker itself from
somewhere in MPM modules, and you will find the names of this under NGSW worker. This
is stem number one. If you remember, our scheme on what happens on build, and step number
two, Angular service worker itself does it all for us, all this network magic. You may
wonder how this manifest looks like. I – as we architect it, the least of the files, plus
their harsh sums, and it’s built based on the configuration file we provide, but actually,
when you just applied the schematics, and this is more or less and less default looking
Angular up, you don’t have to do anything. There is something that we call “smart default,
which are God enough to start with. Based on this configuration, Angular CI generate
settings file or manifest file for the Angular service worker. Now it’s time to serve this,
and, unfortunately, our favourite NG Surf isn’t the salvation here, even in production
mode. They’re too smart, say, to run something that will test Angular service worker, but
what can we do? We can use any of static development web servers. There are plenty of them. Really
nice ones. The least is – the list is for you. Now we’re fully ready to have a look
on our app. Okay. Cache is populated. We can check offline button in a few seconds. Here
it is. Offline. Reload. Yes, that works. So we can say to our offline diner, please go
and take some rest. We don’t need you any more. We will have server not found page enquiry
for our application. Awesome. This was about Angular service worker. And now, the second
time for me to test you. What is here? Workbox. Yes, if the second approach, we go through
today, and, in addition to really cool set of built-in functionality of these features,
it has a real killer one, and we can have our own service worker extended by these features.
Let’s have a look how can we achieve this? First, there are three working modes of Workbox.
I’m a big fan of having it every year from the utility library, so this is not what I
go for. But webpack plugin, maybe I’m not convinced enough to do eject of CLI to set
up service worker. Third option is the node module. I believe this is the one we are going
to use, so let’s install one. We will need this only on build. This is why we can put
it in the developer dependency. This is the script itself. Let’s briefly go through this.
First, we get some method from Workbox git library, right, and based on some configuration,
we inject manifest into something. By manifest, we mean like this. It is very, very similar
to what we have in Angular service worker. It is just differently formatted, list of
resources, and their hash sums. Where do we inject this? Into our own service worker.
So, first, again, similar to NGSW, we have some setting to gently pick the only files
we need for application shell, and power of globes is for us here. We inject everything
into our file, our service worker to date. How this source service worker could look
like, as simple as that. So this is absolutely minimal set-up of Workbox service worker for
providing the application shell. First line, we import the box itself. By default, we do
it using Google CDM, but we can download the files, sort it locally. Not a problem. Then
we have this empty array which injects manifest method. It will be populated by manifest list
we just generated. What it does is two things: first, it builds the array, and, second, it
does simple file operations by replacing empty array with what we’ve just seen. The rest
is done by pre-cache ing and root method of pre-cache ing module. It’s fully responsible
for downloading files, for storing files, for updating files, everything. The last step
we have to add to this flow is to add this step that we will run build script to our
common build flow, and, of course, it’s important to do it after, so, it will go through contents
of this folder, and generate proper manifest for us. Let’s summarise this first point.
What we have in NGSW, Angular service worker, one-liner to start right? No movement from
our side to integrate – all done for us by the schematics. In most cases, we don’t even
have to edit something in configuration for MVP, PWA for the minimal approach application
shell for us. On the other hand, Workbox, it is still exposes quite convenient tool
to build it. And, having a service worker is very important. You will notice this on
our next steps. It was bare minimum of PWA but we forgot about one important UX issue,
right? About the one number 3 to ill trait this. Timeline of our application, we deployed
version 1, we opened in the browser. It’s version 1, right. Next, we updated our type,
fixed some bugs, and had version 2. Our users who opened the version one, second a ago,
a week ago, a year ago, will still see version 1 on the first load. This is well-known trade-off
of PWA in general, and it’s the nature of the application shell, because instead of
going to the network, we grab the files from cache storage on the very first load. Of course,
during this time, when we served everything in the background, we can go and check everything
if it was updated, yes. And, on the second refresh, or second navigation request, we
will see then the version after all. What can we see here? This message. I bet you’ve
seen this message on many websites. That means some facts that you visited this website before,
and that this website was updated after you visited this, and before you visited this,
for the second time, and of course, this is progressive web app. So what can we do in
Angular service worker. You remember the blue background. We use $approach to add some code
to support this functionality. We import special service called the NGSW update. We inject
it in its classical form, and we listen to observable called Available, so all you see
is like true Angular-style code, and if there is an event, we can show this message, and
this way, we cover point number 3 of our dream application shell architecture. My hint for
you: you can provide version description in this prompt, how to do this. NGSW configure
JSON configuration file, there is an optional quality called app data free from object,
so you can add whatever fields you want, change look in my case, and in this available observable,
there is an access to the property of this, so, instead of showing this default message,
we can show something like this. Why not? It could improve the user experience. Switch
to Workbox. We will jump back and forth today. There are two options for you. Number one
is simplest to set up with some drawbacks in a few moments about this. It’s called Broadcast
Channel. This is modern API of the browsers. What we do in our own service worker, for
this precaching module, we have a plugin called broadcasting update. It’s the name of the
channel we will listen into our application. On our app, we add this event listener, and
this is the moment when we can show the prompt that something was updated from precaching.
It works fine but own in Chrome and Firefox. Hopefully, other browsers will implement this
API soon, but if you need to inform the users about the new version, we might want to use
another approach. Where we use service worker life cycle? To be honest, during MVP PWA,
skipped intentionally, one thing in Workbox part. So we have our application. We have
freshly generated service worker by Workbox but they are disconnected, right? If Angular
schematics injects the code for us in case of Workbox, we have to do it manually. Let’s
showcase very naīve version of this registration. Naīve, but still containing feature detection.
First would be , we can improve this, and, second, on this flow, we can inject into some
interesting events. So, let’s list our Theresa May requirements for service worker – feature
detection. Obviously, this is absolutely must-have. We don’t want to have console full of red
lines in the browsers which don’t support service workers yet. Next, we have to postpone
service worker registration to the moment when everything was loaded, and, in the best
case, even UI was rendered. Do not compete for network and CPU resources with the main
thread. And, also, on that point, we can hook in the event called service worker update
when the file of service worker is different than the it can updated, and this is the exact
point where we might want to show application updated message. Why? So first, most likely
if service worker updated, we updated some code inside service worker itself, right?
Some functionality. So we added new cool features, and this is a reason quite enough to show
the message that the app itself was updated, but even if we updated the app itself, I don’t
know, some main JS bundle, pictures, all the listed in configuration, the service worker
file also will be updated, like, it will be different. Why? You remember, we generate
this map of file name and hash and inject it straight into our service worker JS. This
is why we can make sure if we updated our app, if we have different build version in
this folder, the service worker will be updated. We can easily and safely use this event. But
if you don’t want to go deep into all the details of service worker life cycle, I could
recommend you to use another very, very small library, it’s like utility, called Register
Service Worker. Just put it in the correct place, and in case of Angular, the safest
place to have it is promise from bootstrap module. Why? Because the UI is rendered, and
this small utility is responsible for the proper registration in terms of wrapping it,
so all the resources loaded, all the UI is generated. Here, we can pass second optional
parameter with callbacks. Some callbacks dedicated to some service worker life cycle events,
and updated is one we need to show up this message. And by the way, this was created
by Evan … who is creator of UGS. This is approach is used in the plugin, and a similar
approach used in PWA plugin for createReact app. So this is a tested solution. Time to
wrap up this chapter. If we need to write some code, we do it in Angular style, and
this is benefit, I believe for us as developers. We know how to do this. Plus, this interesting
option to include version update message also goes for us out of the box without any hassle.
On the other hand, Workbox provides this first two options, and, if we go for broadcast update,
we can use the same approach to follow updates of the other cache, not only what was precached
but what was changed during run time. This is our next chapter, how it goes when we need
to manage when we need to cache, and reserve some requests outgoing from our app which
are not part of what we call application shell. In most cases, of course, this is related
to our API calls but not limited, so any other calls, so we do from our app. Angular service
worker, it is all about two main strategies: about how we configure these strategies, one
called Freshness, and in other terms, this is a network-first, when we go to try to try
network first, if resources available, we serve this, if not, we fall back to the cache.
Second one called Performance. And it works vice versa. So this is a cache-first approach,
when we’re good enough to test what’s pre-cache ed, and I believe this will work mostly for
some not so often updated resources, like something for archive. This is why I use this
as an example. Yes, this is JSON configuration. It provides some pattern for behaviour. Good.
My hint here: what do we do if we pre-cache ed, just imagine some JSONs from our product
catalogue, and we changed the format afterwards, we updated our client-side application, what
do we do with this old JSON store somewhere on the old user machine, most likely the newer
version of our app, if we change the format, we will not be able to parse this. There’s
an answer, optional parameter, you can pass to the data groups property, and, if you update
it, it’s integer. Angular service worker will ignore what was served before and it will
start a fresh life. Workbox. Similar approach, but way more flexible. So, first, yes, we
have strategies, and we have way more strategies in the Workbox. Network first, cache first
can be network only, cache only, while we validate the strategy used mainly for application
shell, but more interesting that you see, we do not provide it in the form of JSON,
this is code-based configuration, and it gives us the possibility to inject our own plugins
into this flow, so we cannot only fine-tune some settings, we can provide our own logic
for this, and what is our benefit of these two approaches? In Angular, you don’t have
to code to provide this functionality, plus this interesting versioning safety switch
Workbox, right of strategy, so we can pick the one you need, and injecting your own logic,
which is very, very important. For example, if you want to provide your own handlers for
some features of service workers. Push notifications. Very briefly. Angular service worker gives
us the possibility to register it using Angular approach again. It’s about subscription. Sending,
we have to do nothing. We just have to follow a simple convention called notification property
in our back-end, we have to wrap the data to a special field called notification, and
that’s it. Workbox does not provide anything related to push notifications. This is good
and bad. Bad, we have to write everything ourselves, and in service worker, we have
to provide this push event with show notification, but on the other hand, we are free to provide
any logic for other parts of notifications API, like notification click and close. This
is way more flexible. At least, everything here. Great to start with push notifications
in Angular service worker, both on subscription and especially on sending, like literally
have to do nothing on, notification click is going to be released in the next version,
so very soon. Workbox, again, full power and flexibility for us. We are at the final point.
Let’s at least the summaries. NGSW – really easy to start, one line. Easy to integrate.
You have to do nothing to integrate, right? Basic features, you don’t have to write code
at all. If you have to write the code, you do it in Angular way. So, I call this approach
“add configure” and configure is optional. Workbox: framework-agnostic. So all the knowledge
you got about this is applicable to any framework or to no framework at all. Functionality is
very rich. We didn’t list everything what is included. If we provide configuration,
we provide it in the flexible possible way. We did inject a variety of built-in and our
custom plug-ins, and full, full power of our service worker, which we own. I call this
set-up configure code a bit, and get what you want. What to use in this or that project? Up
to you. I will leave you with the question. I hope I inspired you to test both approaches.
On that, thank you very much. [Applause].

Author:

3 thoughts on “Building an Angular PWA: Angular Service Worker or Workbox? | Maxim Salnikov | #AngularConnect 2018”

  • Thank you very much for the great overview. One thing left to mention (not sure whether it was available in 2018) is background sync available in workbox. Being able to cache POST requests in offline mode was the reason why I switched to workbox (https://github.com/angular/angular/issues/22145 ).

Leave a Reply

Your email address will not be published. Required fields are marked *