[MUSIC PLAYING]
ROB DODSON: Hey, everyone.
What's up?
It's Rob Dodson.
Today on Polycast, I'm going to show you
how to take your entire application
and make it run offline, all without writing
a single line of JavaScript.
This is crazy, wicked awesome stuff,
so follow me and let me show you how it's done.
So this is your web page today.
When it needs an asset, it goes off
to the network to request it.
A network fetches that asset and then returns it
so it can be displayed on the screen.
But as we know, this back and forth is not always so perfect.
Sometimes the request could take a long time
to get to the network.
And maybe the network takes a long time
to send the response back, or it takes a long, roundabout way
to do so.
Perhaps the user loses connectivity along the way,
dropping from 3G to EDGE.
Or maybe they lose connectivity entirely, in which case
the network is just unavailable.
So there's a lot of reasons why this back-and-forth dance is
not always as seamless as we would like it to be.
Now let's look at the same model, but this time
with Service Worker.
So Service Worker is a new standard
that acts like a proxy, letting you intercept network requests
in JavaScript and then allowing you to handle them
how you see fit.
So the user makes a request, which flows through our Service
Worker.
And when the response comes back from the network,
the Service Worker can decide what it wants to do with it.
It could, for instance, create a cache
and actually store the response in that cache,
and then return it to the user.
So the next time the user makes a request for the same asset,
the Service Worker can check the cache,
see that it's inside of there and return that instead
of having to hit the network.
This basically enables a really nice offline model.
Now, there are a bunch of other things that you could do here.
You could have the Service Worker
hit the network and the cache at the same time
and make the two race.
There's a ton of patterns that are detailed by my friend Jake
Archibald in this offline cookbook,
and I really encourage you to check that out
after you're done with this video.
But what if you're in a browser that doesn't have
support for Service Worker?
Well, in that case, you just go back
to the way things were before.
Your page tries to hit the network,
and the network sends back a response if it can.
Nothing breaks in this model, and in that way,
Service Worker is just a progressive enhancement.
And that's why Service Worker is kind of brilliant.
If you have a subset of your users
that can support Service Worker, well then
they get an enhanced experience, something that's
a little bit more engaging.
And for your users that can't support it,
because perhaps their browser doesn't implement it yet, well,
they're going to get the same experience that they get today.
So it's not a matter of choosing whether to use
Service Worker or not.
Instead, you can look at Service Worker as an additional layer
that you can add to your application
to give some of the users a much better experience.
I think this is pretty awesome.
And if you're interested, there are actually
strategies around using things like App Cache as a fallback
if Server Worker is not supported.
In general, if you're interested in learning more,
there's this really great write-up
by Matt Gaunt, which goes into a lot of detail.
There's a lot of really good material out there,
so after you're done with this video,
definitely go do a bit of additional research there.
Now, to set up your own Service Worker
usually involves a fair bit of code.
You've got to configure your registration and [INAUDIBLE]
and caching and la-la-la.
It's just, like, crazy.
Now thankfully, there's an element for that.
Thanks to the new Platinum Element collection
from the Polymer team, you actually
get Service Worker support for free.
It's already set up in Polymer Starter Kit,
and so I'm going to show you how to use it.
This is what we're going to build today.
It is a very typical Polymer Starter Kit app.
You can see here, though, that as I'm using it,
I can set it to Offline.
I can then go and click around and use the app,
and it will continue to work.
I can even click this button to load an image of a map
from the network, and that works as well.
So how do we do this?
Well, the first thing you've got to do
is go and download Polymer Starter Kit.
You can grab it off of the site at developers.google.com.
Then you're going to want to go to the GitHub page
for Starter Kit and check out this guide on enabling
Service Worker support.
It's actually pretty easy.
You just need to uncomment a few lines of HTML
and then add this little precache gulp
task to the bottom of your build file.
Now, some of you might wonder, why is this disabled at all?
Why not just have Service Worker running by default?
And in fact, in previous versions of Starter Kit,
it was enabled by default. But what we found
was that can be very confusing for users
who weren't expecting Service Worker to take over
their local host port.
And suddenly they were developing
a completely separate site, and they
were seeing the offline version of Polymer Starter Kit.
So because there was some confusion around that,
we decided to make Service Worker support
an opt-in feature.
So that way when you're using it,
you know exactly what you're getting.
OK, let's go through the steps to add Service Worker support.
The first thing we're going to do
is hop into our index.html file and scroll all the way down
to the bottom of the page.
And you'll see this block of commented text here.
So uncomment that.
Inside of here, we've got a paper toast,
which is a little notification that
will display in the corner letting the user know
that their app works offline.
We've got this platinum Service Worker register
element and then a platinum Service Worker cache element.
So the Service Worker register element
is what is actually going to create and register your Server
Worker in the document.
It has a few important attributes I want to detail.
The first is this auto-register attribute.
This tells the element to go ahead and actually set up
the Service Worker and kick it off.
If this was not here, you would have
to write a little bit of JavaScript
to get that process going.
This skip-waiting attribute tells the Service Worker
to skip the waiting phase and go right to its active phase.
Normally during a Service Worker update,
it's going to wait to see if all of the user's tabs are closed.
You know, you might have multiple tabs open
on the same site.
It would wait to see if all those were closed
before trying to activate.
In this case, we're saying, don't worry about that.
It's OK if they have multiple tabs on the same page open.
Just go ahead and do your thing.
This last one, clients-claim, tells the Service Worker
that once it is activated, it should go ahead and immediately
take control of the page and start
intercepting fetch requests.
So combining these two is a pretty powerful pattern.
Now, the cache element that you see down here,
it's going to handle adding files to the cache
and returning those to us.
And it's got this default cache strategy, which right now is
set up to be network first, meaning
it's going to go off to the network, and if something 404s,
then it's going to hit the cache.
You could set this to cache first,
or you could even set it to, like, cache only.
There's a few different strategies here
that you can work with.
Lastly, you've got this precache file attribute.
And the precache JSON here is a manifest file of file paths--
it's basically an array of file paths--
that we want the Service Worker to precache
for us once it boots up.
So these are things that maybe the user hasn't even seen yet
but we just know they're going to need,
so we're going to tell the Service Worker,
grab all those assets as soon as you start.
I'm actually going to come back to this in a little bit,
but let's move ahead now to look at what
we need to do to get the rest of this working.
So over near elements HTML file, we're
going to go down here a little bit,
and we're going to uncomment these two imports.
These are for our Platinum Elements,
and now they can load into our app.
We can run gulp-serve.
We can boot up our local server.
It's actually going to open the browser for us when it's ready.
And then we can see our app here.
We'll notice in the bottom left that we
get this notification that caching is complete
and we are working offline.
And, in fact, we can verify that by opening up our dev tools
and turning on Mobile Emulation mode.
And you can see I'm going to go in here.
I'm going to use the network throttler to throttle
the page so that it's offline.
And then we can refresh.
Our content will continue to load.
We can open our sidebar.
We can click around.
You can see that the different routes are loading.
So this is looking pretty good, but we go to Contact page
and we click this little button down here,
and our image is giving us a 404.
So what's happening?
So at this point, Service Worker is dynamically
caching assets as the user is navigating through the site.
But what I want to do is ensure that that map
is available to the user even if they haven't actually
visited that page yet.
So to do that, I'm going to have to tell the Service
Worker to precache an asset.
Let me show you how to do that.
OK, so the asset that we want to precache is this map JPEG file.
And if you recall, I said that there's this precache JSON
thing, which is like a manifest of files
that we want the Service Worker to cache for us
even if the user hasn't seen them yet.
So if we wanted to add some files to that,
a really simple way to do so is to add another attribute
to this element.
And this attribute is just called precache.
And we can pass this attribute an array-- that
is, a JSON array.
So notice how I'm using single quotes on the outside
here so that I can use double quotes on the inside.
That's because JSON only takes double quotes.
We can give it a JSON array of file paths
that should merge into that precache JSON.
So with just this one file path here,
my app is actually all set up and everything's going to work.
But as I was doing this, it really
got me thinking, like, what's the deal with this file?
Like where does it come from?
How is it built?
What's inside of it?
So for that, we're going to go inside of our gulp file.
And we've got this precache task that we
can look at inside of here.
And what it's doing is it's building
a little glob of file paths.
And a glob, if you've never heard of that before,
is basically an array of file paths
that are generated using this string.
And this string is sort of like a regular expression.
It says, match anything in the elements directory, anything
in the scripts directory, anything in the styles
directory, any subfolders, any files in there.
So it's pretty wide open, anything
in any of those directories, match it and add it
to this manifest file.
We've also got this line right here
where we're pushing individual files into that array,
like our webcomponents polyfills and our index file.
So if you needed to do something like cache
an entire folder full of assets, rather than put that
into the precache attribute in our HTML,
we could actually drop it in here.
We can say, cache everything in the images directory.
That's one option.
And if you wanted to pass just individual files,
another option would be to add it to this little push call.
You could do this, although it's probably
easiest to just do this in the markup
because it's just a single attribute there.
But I wanted you to know about how this thing worked
and the options that are available to you.
And the last step in this process
is to make sure that we have enabled
the precache task to run inside of the gulp default task.
So we'll add precache here.
And what this does is it ensures when someone
is doing a distribution build that it generates that precache
JSON file for them.
At this point, we're done.
Everything is going to work.
We can hop back over to our browser.
We can refresh the page.
You'll notice that I've set throttling to Offline again.
And I can go and click around.
And as I get to that Contact section,
I can click on the Show Me the Map button.
It's going to hit the network or, in this case, the cache,
and load in our map image.
So like I said, this is freaking cool.
You've got your entire application working offline
and you didn't even have to write
a single line of JavaScript.
It just magically happened, thanks
to the power of web components and Service Worker.
That's it for today, folks.
If you have questions, please leave them down
in the comments.
I do try to read all those if I can.
Also, be sure to click that little Subscribe button so you
don't use miss any episodes.
Again, thank you so much for watching.
I'll see you next time.
Hey there, Polycasters.
Rob here.
Q&A time.
This week's question comes from Dr. Robrez-- so hi there,
Doctor-- who asks, in Polymer 1.0,
can we do data bindings inside of our styles
like we used to be able to do with the old core style
element?
Or is the recommended approach to do data bindings inside
of your class names?
So, for instance, you might have like class foo bar
and then a data binding for another class called baths.
So a really good question there.
In Polymer 1.0, you cannot currently do data bindings
inside of styles.
That is something that we're thinking
about putting on the roadmap, but right now there's
no real ETA for that.
Also, you cannot do binding expressions inside of strings.
So the recommended approach is to take your entire class list
and generate what is called a-- or I guess what we're calling--
a computed binding out of that.
So you can check out this link right here
to read about doing computed bindings down in the docs.
These are pretty cool.
You can pass arguments to them and it
can return a string, which will fill out your entire class
list for you.
So really awesome question.
Thank you so much for sending that in.
If you have questions, please leave them down
in the comments.
We try and read and answer all those if we can.
And maybe we can feature you on the next episode of Polycast.
Again, thank you so much for watching.
Be sure to click that little Subscribe button down there,
and I'll see you next time.