Streaming Service Workers: Live Code Session – Supercharged

Streaming Service Workers: Live Code Session – Supercharged


SURMA: It is 2:30 PM,
and that means that it’s time for “Supercharged.” Hi, I’m Surma. JAKE: Oh you want
me to say my name? Look, I’ve never
done this before. Look, have you not noticed? Different person
standing here today. SURMA: That is a very long name. JAKE: Hi, I’m Jake. SURMA: And today we’re going
to do some streaming Service Worker. Cue the jazz. [JAZZ MUSIC PLAYING] So, Jake, welcome. I’m actually really excited
about this because to me it feels a little
bit like an upgrade because not only do you know
Service Worker, you actually kind of design them,
and you have hair. JAKE: Yeah, that’s true. Well, a little bit. It’s a slight– are you just
easing into someone with more and more hair and eventually– SURMA: Yeah, like, eventually
I’m going to have– JAKE: A full head. SURMA: I’m going to have
a fro, and it’s going to get really interesting. So we already said in the
teaser that we are going to do– or you are going to do– a blog with a streaming
Service Worker. JAKE: Yes. SURMA: So what– I mean, I know streams. I know Service Worker. But when you say streaming
Service Worker, what exactly, like, do you mean? JAKE: OK, so Service Workers
are streaming by default. Like, if you do like a fetch and
you pass the response back to the page or like, if you
get something from the cache, that all streams. You know, it means
that the page is not receiving bits of the
response while the Service Worker’s still busy. SURMA: So something could– the end of the page doesn’t need
to arrive for the first parts to appear on screen. JAKE: Yeah, absolutely. And this is really useful
if you’ve got a long page. Like even something
like a news article, it means that you only
have to receive the top, and you can start reading
it even though you’re still downloading the
rest of the article. SURMA: But when you
say, Service WorkeR IS streaming by
default, then why is what you’re doing,
in any kind, difficult, or worth putting
on a live stream? JAKE: Well, OK, SO
what we’re going to do is we’re going to make
a single stream that’s built up of different streams. So we’re going to
take some stuff from the cache and some
stuff from the network, and we’re going to merge
it together in one stream and serve that up. And that will mean that we
can get on screen really quickly with the cache stuff. SURMA: And that’s important
because usually we want to– we’re telling people
over and over, like, the time to first paint
or the first meaningful paint is super important. If you’re onscreen
quickly and keep the user busy with just
consuming, mostly on a blog, especially with a content
while the rest spins up in the background, that is a
super good user experience. JAKE: Yeah, and it improves
the perception of performance as well. And it also gives you an
opportunity to kind of– say, if the stuff from the cache
arrives and the network stuff’s taking a while, it gives
you the opportunity to kind of put messages up there
going, hey, we’re still trying. SURMA: OK, yeah. JAKE: You know,
that sort of thing. SURMA: Which again,
is better UX, right? JAKE: Yeah. SURMA: So I mean,
with you being here, it makes sense that you
do the coding today. JAKE: Yeah. SURMA: And that means
that I will be– as one person usually does on
the “Supercharged” livestream, I only want to
hang with the chat. So everybody, hi. Welcome. If you have questions any time,
just put them in the chat. I’ll try to keep up
with whatever you say, and incorporate it, and
distract Jake whenever I can, make him stumble, make
him do mistakes because that’s what you want to see, right? So I’d say, let’s just
get into it, and see– where are we starting off? Because I know– are we
going to do it from scratch? Are we going to take
like a starting point? JAKE: Well, so a lot of Service
Workers articles I’ve seen, they do start from scratch,
but I think like most of us, we have the science already. SURMA: That’s a good
point, actually. JAKE: Yeah, so I want you to
kind of start with something and show how you
could add a Service Worker without disrupting
how the site already works. SURMA: Yeah, why don’t you
walk us through it, I guess? JAKE: Right, OK. So like on my screen right now
is what looks like my blog, although I’ve recreated it. SURMA: Hashtag
shameless self-plug. JAKE: Yeah, it’s a self-plug. It’s also my personal brand. But it’s an existing site. This is how it works. And we’re going to be able to
add a Service Worker to it. And I wanted it to
be something that was kind of more site-like
than an app and also something that would benefit
from streaming, so something with
articles as well. SURMA: That makes sense. JAKE: –that doesn’t
have any of the kind of legal problems of showing
an actual news website or something as well. So yeah, this is it. You can sort of click into
articles and go around, but I guess the important
bit is how it’s implemented. SURMA: Yeah. JAKE: So if we dive
into the code here, this is a Note JS project
built on top of Express. SURMA: Which we
have used before. I think whenever we did any
kind of backend work with Node, I think we have
used Node in the– Express in the past,
so it shouldn’t be– everyone should at least, like,
know roughly what the API is. I’m just going to make
that assumption here. JAKE: Well, but, yeah,
my blog in real life is actually built on top
of Django and Python, but I thought like, let’s
stick to JavaScript everywhere. SURMA: Yeah, that’s
probably a good call. JAKE: Yeah, also my Python is
a lot worse than my JavaScript, and we’re about to find out how
bad my JavaScript actually is. So most of the
interesting details– so I’ve got this
Post folder which is a directory for each post. SURMA: I see. JAKE: And so we have
like a meta JSON with a sort of title and
a summary description. SURMA: So basically,
it reminds me a little bit of GitHub
pages in Jekyll, but they have the metadata
on the top of the file, while you put them in
a separate file here, which I actually kind of prefer. JAKE: Well, and this is
all server generated, but it could be done as
a static build as well. Having a server
here means it’s not as easy to see quick changes. It’s not going to have– SURMA: That makes sense. JAKE: So we can see
where a post is built. So I got this roots
JavaScript, and this is where all the roots are. The important one that we’re
going to look at is this one. So this is the roots
for an article. So we can see here, it’s built
like, we get the [INAUDIBLE] SURMA: Oh, the typical
blocked path thing– JAKE: Exactly. SURMA: –with a weird
regex or whatever. That’s not even the proper– it is a regex, isn’t it? JAKE: Well, it’s the
one that Express uses. SURMA: Oh, it’s the
weird thing that you can capture parts of the thing
and put them in a variable. JAKE: Yeah, so that’s the name
of the thing we’re capturing, and then that’s
the regex for it. So a number four times,
and then the slug. Is a slug a word that’s used
outside of, like, Django? SURMA: Yes, I definitely know
that it’s in Jekyll as well. Hugo uses it as well. Maybe they started
it, but by now, it’s a de facto technical term even
though I still think, slug, is it a word? JAKE: It’s fun to say. So yeah, and then it’s just
going in and picking up those files. If it doesn’t find
them, it will throw a 404, which will get
picked up later on, and then it’s going to
pass all of the details it finds into a
templating engine. The content is passed
through marked, which is a markdown
processor, and that will appear on the page. The templating system
I’m using is Nunjucks. SURMA: Oooh! JAKE: Have you came
across that one before? SURMA: That is an implementation
of an originally Python templating language, isn’t it? JAKE: So you can
see where I’m going. SURMA: I think they’re
called Nunchucks in Python? JAKE: Oh, well, in
Python, it’s Ninja. SURMA: Ninja. JAKE: So I’m coming from
Django templating language. It’s very similar. I just meant like a copy and
paste where I already had– SURMA: Because you’re really,
really lazy, aren’t you? JAKE: Well, that’s the– best kind of developers
are supposed to be lazy, is that true? SURMA: It is actually true. Like, if you’re
lazy, you’re going to automate whatever
you can automate. JAKE: And that’s
what we can see here. This is a post,
and it’s just all of the stuff coming out there. And yeah, and that works. SURMA: So in its current state,
you’re doing the actual stuff on the server. You probably have like
a header or a footer. JAKE: Yes. SURMA: And that is
being stitched together on the server side, and an
entire page is being shipped. JAKE: Yeah, so this is
the base here, and the– SURMA: The buttery biscuit base. JAKE: The buttery biscuit base. Look, you need a new
set of catch phrases now you’ve got
someone else here. So yeah, you’ve got
these blocks here, and you can replace those
blocks into the template– SURMA: I see. OK. JAKE: And that’s how it works. So if we’re going
to add a Service Worker TO this project– or well, indeed any
project– step one has to be get your caching
fixed, get it all correct. And I tried to
skip that for this. I thought, well, I’m not going– I don’t want to have to talk
about lots of like normal HTTP caching, so I’ll
just hack around it. And then I kind of
realized that I’m writing so much code
working around bad caching, I should follow my
own advice, so we’ll get a caching [INAUDIBLE]. SURMA: That is actually
really good advice because we keep seeing
websites that use caching– trying to work around
caching rather than fixing it and try to do this– like, with cache
busting, whenever you have to do cache busting
that is a smell that you probably just need to
adjust your caching headers in the first place. JAKE: Absolutely, yeah. And so that’s what I did. That’s kind of preprepared
because a lot of sites have this sorted already. And so we can see the CSS there. The picture of me all
has like a version number there in the URL, so
that’s all taken care of. The CSS– well, anything
with a version number and URL is cache controlled for a
year, whereas everything else with static URLs, like
the actual HTML itself, is cache controlled. No cache. SURMA: That makes sense. Actually, I think we have a
microchip coming up on this– JAKE: Oh, good throw forward. SURMA: –on this topic as
well, so keep your eyes on the channel, which also
means you should totally subscribe to this
channel, so that you know when these videos come out. JAKE: How professional. SURMA: I know, right? JAKE: That’s really good. SURMA: It’s not the first
time I’m doing this. JAKE: Like and Subscribe. Excellent. SURMA: In case you were
wondering, the code is also– is the code going to
be on GitHub later? Can we put it in our Super– JAKE: Oh, the codes on
GitHub now, so yeah. SURMA: We’re going to put in– the bits we are writing today,
or that Jake is writing today, we’re going to put it in the
typical UI elements [INAUDIBLE] repository that we have for
our “Supercharged” episodes. I’m going to link to
it in the description so you can find that
later and follow along if you want to reiterate
what we’ve been doing. JAKE: So shall we add a
Service Worker to this project? SURMA: Yes. JAKE: Yes, let’s do that. SURMA: I give you 20 seconds. JAKE: Can I code
while on camera? That’s the question. Because I can’t
code in real life, so maybe the camera will help. So I’m going to create a
directory here called– SURMA: We have a first
question, actually, and it’s something that– JAKE: That was a mistake. SURMA: Whenever
I watch you work, it’s something that’s
been driving me mad. “Does Jake know that you can
press Command Alt+I to open Dev tools?” JAKE: No, I never do that. I always go for the right-click. SURMA: I’ve been driven
mad by this as well before. He always clicks. JAKE: And I type
with one finger. SURMA: All right, so we’re
going to start with the Service Worker. JAKE: Yes, so and
I’m just going to– SURMA: And that
apparently, is actually going to be written from
scratch, which is cool. JAKE: I already can’t type. Look at this. It’s like– uh. It’s not– SURMA: Well, to
be fair, you still have a lot more
typos in your code until you’re actually
worse than Paul. JAKE: Oh, OK. Fair enough. So it’s not that
I’m bad at spelling, it’s that I have
[? raised ?] conditions in my fingers from my brain. There we go. Let’s just do, [MUMBLING]. Excellent. SURMA: Isn’t it
called console.log? JAKE: Oh, my god. I’m so happy you are here. SURMA: Have you ever
written JavaScript before? JAKE: Never. This is new for me. Excellent, OK. So now I know this
isn’t going to work, because I haven’t created
a root for it yet. So I’m going to do that now. SURMA: Oh, so you
don’t have like– you have noticed the
static middleware is not involved at all? JAKE: So I do use the
static middleware, but alL THE static
files are the ones that are getting the
version number added to them automatically. SURMA: Oh, the revisioning. JAKE: Yeah, so I’ve got
a Static folder here, and then the builds–
the sort of build system that there is, it’s kind of
going and sort of renaming all the files. SURMA: And that allows
to put like an expiration date of like a year on it
because if the file changes, the name will change, and that
means it will never clash. JAKE: And an important
detail is that you don’t want to do that
with a Service Worker. SURMA: Yes. JAKE: You generally
want your Service Worker to be no cache because
like, the browser is going to go to that same URL where
it previously got the Service Worker to look for updates. So you don’t need to
be revisioning it. SURMA: I think every browser
will recheck after 24 hours no matter what the
caching header is, but sometimes that
is already too long because sometimes
a person might be stuck on the old version of the
Service Worker for 24 hours. JAKE: Yeah, if you
break your site, you don’t want it to
be broken for a day. So I always use no cache. I’m going to stop it right here. That should be JS,
and there we go. See, I’m already getting
loads of things wrong. Right, so I want to
serve up that file, so I’m going to create an input. And we’re going to use
stream straight away. We’re going to use
it straight away. SURMA: Oooh, look at that. JAKE: And I’m going give
it a directory name. Go up one level
because we’re currently in this Server directory. SURMA: Are you going to do
any processing on the Service Worker file? JAKE: Why don’t you wait? Why don’t you wait? SURMA: Sorry. JAKE: Look, I’ve got– I’ve got some notes, and
a good order to do things. SURMA: He has notes. The only reason I’m asking is
I always do response.SendFile– JAKE: Ah, yes. SURMA: –which is
the lazy way, but I feel like if you’re
going to do this, then you probably want to do
some processing at some point. JAKE: That is true. So yes, I’m doing sort
of streaming stuff now because that will
become useful later on. SURMA: I see. JAKE: Well spotted. So I should just be
able to pipe like that. SURMA: Just to be clear, I don’t
know what he’s doing today. I have not seen whatever
he’s going to do. Only he knows. JAKE: Well, I wouldn’t
even go that far. SURMA: Maybe he does. JAKE: So yeah, we now have
like Service Worker all connected up. So we should get it to
actually do something. SURMA: Well, I guess you would
actually have to include it. JAKE: Yes, we will do that as
well, but should we do that? Should we do that first? SURMA: Why not? I mean, it’s interesting
because when I first learned Service Worker, I was
like, can I do console logs? Will I see them? It’s a different thread, right? It’s like completely
independent. But it turns out,
as we will probably see in a couple of seconds,
that you can do console logs and see them in dev tools. JAKE: Spoilers. SURMA: Well, I mean,
imagine how developers feel if they couldn’t console log. Personally, I don’t
ever use a debugger, but I use console logs. And I actually have a lot of
beef with a name “debugger” because it doesn’t
actually debug. The only thing it
does is it makes– it slows everything down, so you
can watch a creation fall apart over a long time, so you can
find out who the culprit is. And it turns out, the
culprit is always yourself. JAKE: Absolutely. SURMA: So you might as well
just replace the window with– it’s you. You made a mistake. Fix it. JAKE: So what I’ve
done here is, just in the base template which
is used by all of the pages, I’ve just put a little
script on the bottom there. SURMA: That’s what’s called
progressive enhancement, I think. JAKE: Yes, also with the
If statement for browsers that don’t support
Service Worker, that’s there to catch those. So yeah, we should now be able
to see in the console– ah! SURMA: Interesting. JAKE: Yes, OK. So scripts don’t have
strict MIME type checking. By default, module scripts do,
and Service Workers do as well. And I haven’t actually set
up a MIME type for that. So back in the old
roots, I am going to set the content type header. SURMA: So basically,
a Service Worker file will be just
straight-up declined if it doesn’t have
application/JavaScript as its content type header. JAKE: Absolutely. Oh, well, it needs to be one
of the valid JavaScript MIME types. And there’s multiple
of those as well. SURMA: OK, yaeh. JAKE: But yeah, so
the idea is it’s a security measure because
we don’t want like, if you have an XSS,
we don’t want someone to be able to take one
of the things they made, like a text or a
post or something, and sort of be able to register
that as a Service Worker. So yeah, we can
see now we have– SURMA: We got a console log. JAKE: A console log, excellent. I suppose you probably want
something more than that? SURMA: Does it work offline yet? JAKE: The console log will. SURMA: Amazing. JAKE: But so far, that’s it. OK, you want something
working offline. Let’s do that. So with Service Worker,
you get a fetch event for every request
for one of your pages but also for every request
from those pages as well. So I’m going to– SURMA: I’ve recently read
some of your code, and I– for some reason, it is totally
ingrained in my muscle memory to always type
Self.AddEventListener and Self.SkipWaiting,
whatever that is. That is not necessary. Self is basically the equivalent
of window on the main thread. Everything that is
defined on Self, a window will just be available without
typing out Self, a window. JAKE: And I find that
developers, myself including, are entirely inconsistent on
when they put like a window at the start and
when they don’t. So what I’m doing
here is I’m just going to respond with fetching
the thing that the browser’s asked for, so that will be
just kind of transparent, so it’ll do the normal thing. But I’m going to catch it
in case it doesn’t work, which offline would
be one of those cases. And I’m going to
create a new response and just say like,
this is offline. SURMA: Ah, so when it fails
the Catch Handler will trigger. JAKE: Yes. SURMA: And will instead just
return with, you’re offline. JAKE: Exactly. SURMA: So now we have–
basically we just made the blog work offline. JAKE: Yes, kind of. Well, there’s one thing that we
need to sort of watch out for. So we can see– so this is the
Service Worker that failed because of the MIME type,
so let’s just get rid of that. This is the Service Worker
that they’re using now. Now if I refresh the page,
what’s going to happen is that new Service
Worker that we just added is going to come
in, and it’s going to be waiting to activate. So Service Workers,
by default, they don’t get rid of the old
version while it’s still in use, and it’s still in
use by this page. SURMA: Why is that, though? Like, why can’t
they just take over? JAKE: So another thing that,
as developers, we don’t really like handle very
often is the idea that we can have like
three different versions of our app running at once. SURMA: Just imagine multiple
tabs I guess, right? JAKE: In multiple tabs where
one’s been open for a while, you open a new one, that’s
kind of using new stuff. SURMA: I noticed people have
opened so many taps that you can’t even see the path icons
anymore– the path icons– and then you just
open a new version because you forgot it’s
already opened somewhere else. JAKE: Well, when
I get to the point where it starts looking
like a table of elements, that’s when I abandon it, and
I just need to close them all. And if I don’t know what they
are, will I really miss them? SURMA: No, not really. JAKE: Well, the
answer is usually yes. So I’m going to skip the
waiting phase on here, and we’ll be doing
that with code shortly. But now we should have a
site that works offline. So if I click offline on
there and refresh the page, it says, [? user ?] is offline. There you go. SURMA: Perfect. Ship it. JAKE: Are we done? Do you want more than that? SURMA: Well, it’s
not streaming yet. I mean, it is kind of
streaming but not really. JAKE: Not really streaming. That is fair enough. SURMA: We have to hold
up that promise at least to call this episode done. JAKE: So yeah, I guess we should
do an offline page that’s like within the style of
the [? sites– ?] SURMA: Maybe. JAKE: –that has some design
to it, something like that. SURMA: That sounds good. JAKE: So I’m going
to create that. I’m going to create a page. Let’s have a look. So this, in the templates here,
I’m going to create Offline. I’m just going to copy and
paste one of the things I’ve already got. This is the template for
the post that I’m stealing. The title of the page
is going to be Offline. All of this header stuff
like the meta properties, we don’t need that. SURMA: Who needs that? JAKE: And the title just
like, you are offline. Excellent. And the content, we
can just say like– SURMA: Please go online. JAKE: How do we want
the user to solve this? Like, try refreshing while
waving your phone around. There we go. Which is going to be especially
amusing if they’re actually on desktop when they
do this because they’re hitting Refresh and
waving their phone around. SURMA: Or the captive portal. JAKE: Yeah. So this is– I’m not going to create a root
for this because this doesn’t need to sit at a constant URL. This can be a static
asset as well. SURMA: Yeah, OK. JAKE: So I go along
to the terrible build system I ended up making
for this project, which almost certainly should have
been gulp, or webpack, or something instead. But I thought it would be
simpler to build it myself. SURMA: That’s probably the most
Jake thing you could have done. JAKE: Oh, it ate so much of my
time, I shouldn’t have done it. So yes, I’m going
to add Offline.html. I’m going to send it into
the static rev path with all of the other [INAUDIBLE]
assets, and I am going to render out a template. And it’s the offline one. So when I save that– well, hopefully–
because the server’s going to restart when it
sees that code changing. And if everything has
worked, we should see– yes. So we’ve got like
Offline.html there. And we can see that it’s– [INTERPOSING VOICES] SURMA: And it has all the
nice markup and everything. Cool. JAKE: Excellent. So I’m going to copy that, so
we can see it in the browser. SURMA: Wow, you’re lazy. JAKE: You would remember that? [INTERPOSING VOICES] Right, OK. Let’s see. Oh, look, in my history, I’ve
clearly done this before. Right, and that is– SURMA: That is a much
better offline page than– JAKE: But we can currently
only access it online, which doesn’t feel quite right. SURMA: Well, it defeats the
purpose just a tiny bit. JAKE: So what I’m
going to do is– we need to take
this page offline. We need to cache it. But not just the
page itself, we’ve got these other assets as well. So we’ve got the page. We’ve got like the CSS. We’ve got this
picture of me that should be available
offline, I guess, and these social icons as well. SURMA: I personally
would be very happy if I could look at your
face while offline. JAKE: Well, you can. You know me. That’s something– that’s
something we can just do in the same room together. OK, so I’m going to– we
need to cache this page. So I’m just going to go back
into the old Service Worker. SURMA: Yeah, so
are you just going to straight-up hard
code the assets that you’re going to cache,? Or are you going to
like analyze the markup? OK, keep going. I guess I’m thinking ahead. JAKE: No, you’re right because
this is the problem we’re going to have. Because if I hard code
all of those assets then I’m going to have
to change them every time I make a small
change to the page. SURMA: True, because
the revisions change as well, right? JAKE: Yes, exactly. So what I’m doing here
is Event.WaitUntil, which is– so the
install event, this runs the first time the
browser sees this version of the Service Worker. SURMA: OK. JAKE: And it’s our
opportunity to get everything sort of ready before
the Service Worker starts actually controlling pages. So because I’m from
the future, I’m going to use an
async function here. So what we want to do here
is get a hold of a cache. SURMA: So we have a question. “Are we going to use any tools
like sw-precache or Workbox?” JAKE: No. SURMA: No. And the reason
it’s pretty simple is because this is not
about how to use a library. This is about– we want to show
how these libraries actually work, what they’re actually
doing under the hood so you understand
the concepts more. And then it actually is
easier to use these libraries because you understand
what they’re doing, and how you can debug the things
they’re supposed to be doing versus what they’re
actually doing. JAKE: Yes. SURMA: And also, as
I said, Jake actually is one of the spec authors
of Service Workers. It would be a wasted
opportunity to not actually talk about the low level– the actual API of
Service Worker, itself, and using a library instead. But these libraries
definitely do have a place, so I encourage you to check
them out and make the decision for yourself if you want to,
for production, go this route and write it yourself
or rely on the library. That is up for you to decide. JAKE: Absolutely, yeah. I’d say, I just wanted to
go as low level as possible with this stuff. But yeah, we’ve
now hit the point that you were talking about of
like how do I get those URLs? And when I originally
was playing with this, kind of
deciding how to do it and actually how I
did it on my blog, is I just used the
templating engine that I had sitting there. SURMA: Oh, so basically,
the Service Worker, itself, is the
product of running through a template
engine, and you can add the revisions dynamically? JAKE: Yeah, but
what happened was it messes with all of the
syntax highlighting, the linter was like, um, uh, um. SURMA: Yeah, I’ve been there. JAKE: This is bad. I saw, actually, you were
writing JavaScript with PHP. SURMA: Yes, I just
did that yesterday, and I’m generating
JavaScript with PHP. And that is also just– in
terms of syntax highlighting, and like templating,
and template strings, and JavaScript, it
just gets weird to keep track of what is a
JavaScript variable, what is a PHP variable. It can get really,
really confusing. JAKE: So a kind of solution
around that– all my notes are falling on the floor. SURMA: How could you survive– JAKE: How could I
possibly continue? SURMA: –without these? JAKE: Oh, I’ll find quickly SURMA: I didn’t notice. JAKE: No one noticed. SURMA: So I’m going
to use static module. Have you heard of
static module before? SURMA: No, I don’t think so. JAKE: So this is a
module by substack. I also did Browserify,
I believe, yeah? SURMA: Oh, OK. So Browserify was
basically, I think, one of the first
projects to convert packages with a Node ecosystem
to run in the browser. JAKE: Yes. SURMA: Because Node
would use Require, and it doesn’t exist
on the web platform. And so it would need to,
like, somehow handle that, and that was the project
Browserify, I think. JAKE: Yes, and
static module kind of has parts of that
going on because you can pipe a JavaScript
thing through it, and you can sort of modify parts
of the JavaScript in quite– well, I think is quite
a nice, usable way. So if I do static to cache,
and just for demo sake, I’m just going to output hello. Now once I do
that, these modules are available inside
my JavaScript. All right, so because I
don’t like typing very much, I’m going to copy that. And up at the top
here, I’m going to do– I’m just going to cache. And I can use good old
Require statements. So if I have not
messed it up, what I should be able to do here– right. And we can see that that
whole Require statement has been replaced with– SURMA: Oh, so it just
basically inlines the module? JAKE: Absolutely. SURMA: That is nice, OK. JAKE: Yes, I love it. It’s like if you’re doing
something more involved, then I think like webpack and
things sort of do this better, but if you’re just wanting
to make small changes to– and you don’t want to bring
in the whole of webpack in, I think this is a really
nice, small way of doing it. SURMA: And that
reminds me something we’ve preached probably every
time and haven’t done yet is, this is not
production-ready code. JAKE: Oh, yeah. SURMA: We are going to
write something that works. We’re going to
write something that is hopefully understandable. And I shouldn’t say we. It’s Jake this time– something that you can
read and understand concepts of– probably
that shouldn’t be pushed straight to production. There’s lots of
polish, lots of safety measures that we
are probably going to skip on to keep the
code terse and readable. JAKE: Yeah, and I’d say one
of the things I’m doing here is processing this
JavaScript on every request is part of Express. It’s one of the things that
I would not do in production. If you did that
on the server, you would at least cache it so you
were not doing it every time. Or it would be part
of your build script. And stack module’s compatible
with all that sort of stuff. You can use gulp or whatever
to process these things. SURMA: I see. OK. JAKE: Well, right, we don’t
want to just output hello. We want to output like all of
the stuff we want to cache, so let’s do that then. So I’m just going to create
an array of the things I want to cache, so let’s go for– SURMA: So these are
going to be the file names without the revision. JAKE: Right, because what I
can do then is map it across. So I’ve got like the thing
which did all of the revisioning keeps a hash of all of
those things that I did, so I should just be able to do– SURMA: If you are looking
for the ref package that Jake is using, you can’t
find it because he wrote it, because why wouldn’t he? It’s going to be
in the repository later if you’re
wondering how he did. It’s probably just
tedious to write, not necessarily very
complex, I imagine. JAKE: Yeah, it was
one of those things that I thought– like when I
was halfway through writing it, I was like, I should
not done this. I should have just
used gulp or something. SURMA: Because it sounds
deceptively simple, just hash the contents
and put it in the name. But I’ve been there when you
have like cyclic inclusions or whatever, it
gets really weird. JAKE: And I didn’t
solve those problems, so yeah, if you want
to solve it properly, I would say definitely
use webpack. SURMA: Did I say not
production-ready code? JAKE: Yeah, there’s also
gulp rev, gulp rev replace. SURMA: And that’s
probably one of the most– the older project. He has been doing it for
a while, where you just add these kind of provision
hashes to the name. JAKE: And Django
has their own, and I think Rels has their
own as well for doing the same sort of stuff. So you can see that that’s
sort of stuff’s being output. SURMA: Cool. JAKE: So you know, I’ve got
to do the same for the rest. SURMA: So basically
you’re just going to add a list of
assets that you know we are going to need
anyway to be offline, probably the very minimal set? JAKE: Yeah, it’s
just the stuff that appeared in the
network panel when we looked at the offline page. SURMA: OK, then the
original’s going to be added, and we can just use the
vanilla addAll cache command to just have them all
be cached and be available offline. JAKE: Absolutely, so we can see
that now– like all of those. And I have to say, I agree. SURMA: I like that you actually
called the picture, me.jpg. JAKE: Well, you know. SURMA: It’s not Jake.jpg. It’s not avatar. It’s me. JAKE: No one else
is going to work on the codebase with
my site, so it’s not going to confuse anyone. OK, so yeah, we now have
that variable there. And as you can see, just
like, yeah, off we go. SURMA: That is
actually pretty cool. I did not know
about this module. I like it. JAKE: I love it. But we need to use it. We’ve sort of we’ve
cached all these assets, but we’ve not told the browser– SURMA: Yeah, we’ve gone
sort of straight to fetch and therefore
straight to network when the request comes in. JAKE: Absolutely, so I’m going
to do another [? erasing ?] function because I love them. So yeah, respond with and wait
until, they take a promise. And with install, if
the promise rejects, then it will throw that
Service Worker away. It’s like, oh, this failed. And with respond with, we
want to eventually return a response object. So async functions are a nice
way of being able to do that. SURMA: I love the
async functions. It’s just so much easier to
think about these things. JAKE: So I’m going to do cache
response here, caches.match. Let’s go for– [INAUDIBLE] requests. So here I’m just
saying, hey, do you have anything in the cache
for this thing that’s been requested? Because it will be null if
it doesn’t find anything., which is false here. SURMA: Which is
something that I always have to remind myself
of because sometimes I expect it to throw or
to reject the promise, but that is probably
just for an actual error. JAKE: Yes. SURMA: And that
something’s being cached as an error is kind of
like an expected outcome, which is why it’s returning
null instead of throwing. JAKE: But I’ll tell you what,
it does throw, and that’s fetch. SURMA: Fetch will throw, yeah. JAKE: Yes, because there is
a complete failure to fetch, so yeah, it will throw away
some promise or the reject in async functions, that
that becomes a throw. SURMA: So somebody asked, “How
does that pipe code actually work? I have not used pipes before.” Those are, as far as I know,
the old stream implementations of Node. So Node had dreams before
the Web Platform did. And they had this concept
of streams that you could pipe into each other. I mean, the Web Platform
now has a similar stream, but the API’s a little bit
different in terms of piping. But if you want to
know more about those, look up the Node documentation
on their streams. Just Google for Node
in streams, then you should probably
be good to go. JAKE: Yeah, it really will
stream right, will stream, transform stream– that’s
all in the Node docs. So yeah, it’s piping
those things together. But rather than passing
the whole thing, it can pass little chunks of
it along and sort of process it in little parts. It’s kind of really
nice memory efficient. So I’ve kind of hit a
little stumbling block because here– so I’m
trying to fetch the thing, and if that fails, I want to
return with that offline HTML. SURMA: Yeah, that makes sense. JAKE: But the best I know
of the URL is Offline.html. SURMA: Oh, you don’t
have the hash once again. JAKE: Don’t have
the revision name. So this is where like
the static module stuff is even more useful. So what I’m going to do
here is correct static. SURMA: So you’re just using
it as a glorified– you’re basically using this so
you can keep your syntax hiding while just using it,
more or less, as a templating engine? JAKE: Yeah. It’s great, isn’t it? SURMA: I mean, this is where
Paul would say, it works, so yeah. JAKE: We don’t speak
about him anymore. SURMA: No. JAKE: So here, yeah,
I’ve created a function, [? revGet, ?] which is just
going to sort of pass it to that thing of like, you know,
give me the revisioned version. So I can just do here– [? revGet ?] equals require. You don’t have to call all of
these modules static at first. I just do to kind of– so when I look at
the code I kind of know which stuff is coming
from– like the static build system rather than stuff
that’s going to be left there. SURMA: Interesting question. Why return a wait fetch
and not just return fetch? JAKE: That is a good point. SURMA: It’s very small nuance. JAKE: Yes, because
if we return fetch, then what it’s
going to do is it’s going to pass the promise back
even if the promise rejects. SURMA: We wouldn’t know if
fetch had thrown or not. It would just be a
promise that rejects. But we want to be
aware of a rejection because we want to catch
it with a Try Catch, so we can handle it. So that’s why it’s
return a wait, which looks a little bit odd, but you
get used to it fairly quickly. JAKE: Yes. So now if I refresh
the page, right, we can see the sort
of static revision, the offline thing is there. SURMA: I’m both
amazed and disgusted by your use of static modules. JAKE: Well, it’s better than
PHP templating, isn’t it? So let’s have a look now. So the Service Worker
should have updated because I’ve reloaded the page. OK, so it’s still
waiting to activate here. Like I said, if you’ve got
multiple versions of your app running, especially if
you’re dealing with data, you could end up with the old
version and the new version clashing and creating problems. We don’t actually have
that here because it’s just a simple site. So what I’m just going to say
here is, skip all waiting, and just call that
as a function. SURMA: See, I would want
to write self skip waiting, but it’s totally unnecessary. You can just skip waiting. JAKE: Totally unnecessary. Saving those bytes. So now we can see the
installing one sort of takes over it instantly. And what should happen if I
go offline and hit the Refresh button. Right. SURMA: I mean, kind of. JAKE: So we’re halfway there. So what has gone wrong? [INAUDIBLE] sheets, but it
transferred with MIME type text HTML. SURMA: Oh, do we actually
block style sheets when they don’t have the right MIME type? I thought we– JAKE: I think it could be a– SURMA: Yeah, I mean, let’s
look at the network panel. If the files are– I mean, yeah. So there is an all.css
being successfully received. That is the Service Worker
trying to fetch it, right? JAKE: Yes. So, oh, that’s interesting. So it’s trying to do that. It’s not finding it,
and it’s falling back to the offline page
even for the CSS. So everything is
returning that failure. SURMA: Oh, yeah, we
don’t quite want that. JAKE: So if we go online
with this, what happens here? SURMA: That seems to work. JAKE: So the URL is correct. So it suggests that
something is going on either with the caching
or with the matching. SURMA: So we got
a cache response, but we just threw it away. JAKE: Yeah, I found
it, didn’t return it. That’s fine. Oh, OK. I was getting nervous there. SURMA: You’re still online,
so it doesn’t count yet. JAKE: So I’m still online. Everything’s fine. If I go offline
now, it should work. Oh. SURMA: That is much better. JAKE: That’s good. SURMA: We were panicking
a little bit there. JAKE: I was little bit
panicking when I got there. SURMA: See, he has a cheat
sheet, but even then– JAKE: I got like
error-throwing sweats going on. So we’ve got this whole
offline thing working now, so that’s pretty good. SURMA: How many browsers
support the async operator? I think we are actually
in a really good state. I think all the current
stable versions support it off the major browsers? JAKE: Yes. SURMA: Let me quickly check,
can I use on the site? But I feel like if you don’t
have to go too far back– async? No, is it Wait? Async functions. JAKE: So it’s everything
except Internet Explorer. SURMA: Yeah, so Edge– JAKE: Edge has it. SURMA: –does. Since the most
recent version, 15. IE 11, which is the last version
of Internet Explorer does not, and all the other browsers,
with their current version actually do. So I would encourage you all
to embrace it and use it. It makes all– especially
with Service Worker, it makes the code much
more easy to think about and to juggle the
things in your head. JAKE: Right. OK, so let’s have a look at how
we’re doing with this stuff. Because one of the things
I’m not happy with right now is that we’re opening
this static cache, right? SURMA: Yeah. JAKE: And that means,
like when we’re updating the version
of that, we’re just going to be writing into
the same cache, which is not so great. And so that means that
the newer thing is going might be overwriting things. It might be messing with stuff. So what we normally do– SURMA: Let me tell
you something. I sometimes struggle to– I always keep
reinventing in my head. If you install a
new Service Worker, do we want to redownload? Do you want to see
what’s in the old cache and manually carry over? And all these
questions that you get. Do we create a new cache
or just reuse the old one? I mean, it can get
weird, in-between states, so let’s see what you’re doing
this time in this version. JAKE: Right, so you can
see on the screen here, I’ve made a version
1, and I’m going to sort of add static version. And that’s going to
be my cache name. SURMA: Don’t you want to
require the versions then because you want to change it? JAKE: Yeah. That is exactly what
we’re going to do. SURMA: We stole the
concept of Jake’s code. JAKE: So what I’m going to
do here is, like– yeah. So updating this version
number time and time again, that’s going to be like
a real pain to do, right? SURMA: Yeah. JAKE: So we want to
automate that somehow. So over in the root file, I’m
going to generate a version number automatically. So what I’m going to do is I
need a version number that’s kind of all of the– it represents what’s unique
about that Service Worker. And it just so happens that
we have a way of doing that, and that’s with the URLs. SURMA: Yeah, OK. JAKE: So this is what
I’m going to do now. So you can talk about it while– you can describe what I’m doing. SURMA: And now he’s
typing a const variable at the beginning. So all of the crypto, that’s
actually a standard Node module, which I’m always
scared of touching because it says crypto. And crypto is basically, you
never want to roll your own, so always rely on available
implementations for these especially if it’s actually
security relevant, which I guess in this case,
it is not really. JAKE: Yes. So let’s have a look at. It’s not roll your own crypto. It’s all there already. SURMA: Yeah, exactly. JAKE: So what I’m going to
do now is create a hash. SURMA: A question on the side. What is the maximum size
in kilobytes, or whatever, that a Service Worker can cache? And that’s actually– it’s
a very hand-wavy answer, I’m afraid. It depends on– you
have to correct me here, but I think the most
recent answer I have is that it is a fraction
of your available space on your hard disk. JAKE: Yes, yes, it is. So the– what Service
Worker can cache is part of like
the sort of general what can the browser cache. So you get a kind of shared
space for Index DB, the cache API, local storage,
all that sort of stuff. What I’m going to do here is–
so I’ve created a hash now. It’s ND5. Let’s not be too scared
of that because it’s not for security reasons. SURMA: It’s not
security relevant. Even though MD5 is
being discouraged for hashing the
contents and having a somewhat unique identifier,
it is perfectly fine. JAKE: Yes. And so what I’m going to do here
is go through all of the URLs that I’m caching. So for each and let’s
go for a sort of URL, and then sort of hash.updates. This is going to add all of
those things into the URL. So this is adding each
URL into the hash. And now I’m going
to create a version from that, which
is the hash.digest, and I take in the hex of that. And that can be the version
number for this Service Worker. SURMA: So you’re creating
a version number. It depends on your– on the static files
that you’re hashing. JAKE: Exactly. SURMA: And since
they contain a hash, that means that your
version number will change even if only the version
one of the dependencies change. JAKE: Yes, I’m
sweating quite a lot. It’s warm in here, isn’t it? SURMA: It always is. You have to imagine, we have
some lights because, otherwise, it would be fairly
dark in here, but I guess I’ve gotten used
to it at this point. JAKE: We can keep the
camera on the screen, so you can’t see how much I’m
kind of actually dying here. Right, so I’m going to
do static version here. And what I’m going to
pass through here is– SURMA: So the reason
you’re doing this– just to reiterate
that I get it right– is you want the version
of your Service Worker to change whenever one
of your static files change because you want the
Service Worker to redownload all the files, in that case? JAKE: Absolutely, absolutely. SURMA: OK, so the
problem would be if we didn’t change the
Service Worker file, I think they always still do
the byte equivalence check? JAKE: It is byte
equivalent, yes, and that’s what it’s
kind of always been. And that’s kind of
like where things will stay in terms
of that, so this is a nice way of
making sure that all of that byte equivalence is– SURMA: So if you have a
Service Worker installed, it’s going to try to redownload
it the next time you visit, I guess, and compare the code
of the Service Worker file, the main Service Worker file. And if they are byte
equivalent– namely, the exact same file– nothing is going to happen. And if the dependencies
have changed, your Service Worker
wouldn’t know about it. So that’s why we want to make
sure that our Service Worker code changes at some point
if our dependencies change. And that’s why we basically use
the hashes of our dependencies in the version
numbers, so we can make sure every change not
only of the Service Worker file but of dependencies will
trigger a redownload of all the necessary data. JAKE: Absolutely. So now we can sort of see
here inside the Service Worker file there. We’ve got that version ID there. And that’s going to be
used in the cache name, and that’s going to carry
forward into the Service Worker, itself. So now if we load the page,
that new Service Worker is going to come in. And I’m going to
refresh the caches here. SURMA: See, that’s the
advantage of the right-click? I did not know that we had a
right-click refresh because I always reopen dev tools. JAKE: Oh, you actually
close and reopen it? SURMA: Yeah, I didn’t
know that there was. Wow, I learned something today. JAKE: Right. SURMA: Amazing. JAKE: But you can see there’s
a problem here, right? The static cache name, it’s
got this sort of long hash at the end of it,
which is what we want, but the old cache
is still there. So I’m going to go over into
the Service Worker code again, and we’re going to fix that. So AddEventListener,
so we’re going to use the Activate event. SURMA: So Install is basically
the Service Worker file has just been downloaded, and
you can hook into this event and run some code to make
yourself– to set yourself up. JAKE: Yes. SURMA: Activate is, once
you’re done installing and the Service
Worker is actually about to take over
responsibility for all the requests
of your sites, that is where Activate
comes in, right? JAKE: Yeah, so at this point
we, know that the old Service Worker is gone, so
we’re in a good position where we can actually start
deleting all of its stuff that it needs. SURMA: I see. JAKE: So let’s have a look. We’re going to do key. So what I want to do
is look through all of the caches that
are there, delete the ones that we don’t need. So if I do a wait caches.keys. Here we go. So that’s all of those now. So I just want to iterate. SURMA: You get a list of all
the caches that are currently available in your cache’s API. JAKE: Absolutely, so I’m
going to go through each one, iterate over them. And if I find one that is– so If key doesn’t
equal the cache name that we’re going for– SURMA: So basically
you’re cleaning up after the old Service Worker. You are the new one. You know what name
your cache has, and that means all the
other old caches can be removed because
you are already done installing yourself. JAKE: Absolutely. That is exactly
what we’re doing. SURMA: OK, I understand. JAKE: OK, so yeah, you
can see that initiative. If it’s one I’m
not expecting, I’m just going to get rid of it. And so hopefully, now,
if we reload the page– SURMA: We should have a new
one, and the two other ones should be gone. That’s what we’re
expecting, right? JAKE: Yes, so if
we go into here– and that is what’s
happened, excellent. So yeah, things are looking
correct, in the right shape. SURMA: It does
look correct, yes. JAKE: So that means that when
we add a file to the cache, it’s going to create a new
cache for that like static with a sort of new hash at the end,
and then it’s going to sort of– it will delete
the old one once this– SURMA: OK, we got two questions. One of them– “Why use a wait on cache.keys? Is that async?” Yes, it is. JAKE: Yes, it is, because
the keys is part of– that stalled on disk, right? SURMA: Yeah. JAKE: So anything
that’s stalled on disk we want to make sure it’s
not going to be blocking– SURMA: Async, because I/O
operations on the disk are– tend to be very slow at least
in terms of web time budgets that we have. I think, actually, almost all
Service Workers APIs are async just so we can have
the opportunity to defer work a little
bit until the browser has time to actually get to it. JAKE: Absolutely. Absolutely. So we kind of–
we got a nice sort of streaming– well,
it’s not streaming yet, but we’ve got this
nice offline page, and we’re controlling
our caches now. But this is the
point where we want to start thinking about
the streaming stuff, right? SURMA: Yeah, because
right now it’s still just entire pages being cached. Actually, not being
cached, but yeah. JAKE: Yes, but if we think
about the pages that we’ve got, we can see sort
of that, you know, this column here
is always the same, so we could we could cache that. And we’ve also got the
header along the top here. This is static as well. SURMA: This very
complex black block. JAKE: That tiny bit there. Well, you know, there’s also
that Jake Archibald wrote. You know, that’s a part– SURMA: Got to put your
name in somewhere. JAKE: Absolutely, so it would be
nice to be able to deliver that before the network. So that’s something that
I want to try and do here, so we can deliver that bit
and then start streaming the network stuff through. A pattern that you might
have heard of to do this is called app shell. SURMA: Yeah, so app shell– I’m going to try and explain
it, and you can tell me if I’m right or not. JAKE: All right. SURMA: Basically, in
the most primitive form, you have your header bit,
and you have your footer bit, and then you have your
content in the middle. But that means that you never
have to actually redownload the header and the footer. I can just get the
content in the middle and swap that out
for the new content. JAKE: Yes. SURMA: And if you do that on
the server side, it’s app shell. If you do it on the
client side, then it’s basically SPA single page
app kind of rooting thing. JAKE: Absolutely, so if we take
a look at this example here, we can see that it’s
got this sort of gap of where the content would be. And a typical way
to do app shell would be to like to cache
this, display this, and then let JavaScript go and sort
of fetch all of the content. SURMA: So while the
fetcher is still going on, we are on like a very slow
network or a network with very long delays, the
user would already see this and be reassured
that actually something is happening, that the
network is working and something is being
loaded, but it just takes a little bit longer. And that’s why the
streaming Service Worker is such a great user experience
because you can see something happening on screen for free. JAKE: Right. Yeah, and the app shell
model, the problem with it is that people like– if JavaScript is
handling that fetch, it needs to download
that whole article and then have
JavaScript put it in, and that’s where
things get slow. And I have a demo of that. If we get to a
position where we can do this one kind
of correctly, we can compare it to the kind of
traditional app shell model. SURMA: That’s cool. JAKE: OK, so the first thing,
I guess, I need to do this, is I need an endpoint
that gets me just this center bit, this
middle bit of the article. SURMA: Yeah, because if
we want to do app shell, we don’t want to
redownload the header. That’s the whole point. So we need a way to get
just the middle bit. JAKE: Absolutely. So I’m going to create
a template for that. So down in my
template system here, I’m going to create a new
file, and that’s going to be [? PostInc. ?] That’ll do. I’m not very good
at naming things. I don’t know why I design APIs. SURMA: Well, it’s
one of the hardest problems in computer science. JAKE: I’m just going to copy
what we have for the post template here and the things
we don’t need because we don’t need this [? extends ?] bit. We don’t need any of
this header stuff. In fact, we don’t really
need the main content here. I’m just going to move that out. So this, this is the
only bit we need. Now we just need to kind of
come up with the roots for that. SURMA: So if you run
into that template there, it’s basically the
entire header is missing. We have no header or footer. It’s just going
to be the markup. By itself, it’s
going to probably look really weird
because there’s not going to be styles there. It’s going to be, you know,
no layout, whatsoever. But once put into the context
of our header and footer, it is going to look great. JAKE: Yes. SURMA: Or like just as
it’s supposed to be. JAKE: Well, we’ll see. SURMA: Let’s not say great. JAKE: We’ll see if we
can even get there. So here in the rooting system
again what I’m going to do is I’m going to– I could create a whole separate
root for these includes, but I’m going to
cheat a little bit. And what I’m going to do is put
a little Include bit at the end there. And the regex for this
is going to be the word “include,” so it’s
literally can only be that. And it is optional. And check out these hacks. SURMA: I love it already. JAKE: The template name is going
to be request.params.include. And if that’s there, we’re
going to use [? PostInc. ?] Otherwise, I’m going to use– SURMA: OK, that’s pretty neat. I mean, so you switch– depending on whether
the input or the include option is present in
the request URL or not, your switch of the
template is being rendered. JAKE: Absolutely. SURMA: Cool, OK. JAKE: I mean, assuming
it works, right? So the good news is no
errors on the server so far. This is the normal
pages I can find. And if I go to include– [INTERPOSING VOICES] SURMA: There’s no styling. If we look at– can you
do Command Alt-U for me? JAKE: So let’s
say Command-Alt-U. SURMA: Got to teach
you some shortcuts. So we can actually
view the source, and you can see it starts
straight with [? a div. ?] It’s like this. All the other stuff is missing. And now if we put that
in between the header and the footer, we will be
back at the original page. JAKE: Yeah, so now we just
need to kind of do the rest. We need the kind
of start and end that we want to– you
know, the thing to wrap it all over around. So we need to create
a template also for the shell, the kind of– the
inverse of that, so this page but with that bit missing. SURMA: Yeah, OK. JAKE: So I have to
do that as well. And it’s very similar to before. I’m just going to call
it– let’s call it shell– or even spell it right,
and let’s have a look now. We’re going to take
the post again. That’s a nice thing
we can copy from. SURMA: Rip out everything
else except the other bits. JAKE: Exactly, we’re
going to come up with the title of
Loading because this is going to be sort of
displayed initially. SURMA: I see. JAKE: We don’t need all
of this header stuff. And this main content,
you can get rid of it, because that’s the post. We don’t have that
to display yet. And this is where we’re going
to put all of the stuff. SURMA: OK. JAKE: And there we go. SURMA: For the people who tuned
in a little bit later, hi, this is a “Supercharge”
livestream, and we’re doing streaming
Service Worker, which basically allows you to stream your
responses to the client, meaning you will be
on screen much faster and give your users a way
better experience without having to do any sort of trickery. Because usually, the
network does it for free, but once you have a Service
Worker in the middle, it is easy to fall
back to easy habits and remove that feature off
the web, which is streaming. JAKE: Yes. So like what we did
with the offline page, we need to put this shell
into the static cache. So here we are in that
little build system again. I’ve copied the line,
and I can just like– SURMA: Even with multi-cursor. JAKE: Oh, yeah. I like multi-cursor. SURMA: I do as well. JAKE: But the problem is,
like, it’s not actually what we want because I want
to do is I want to start and I want the end. SURMA: And right now,
it’s both, right? JAKE: And right
now it’s both, so– [CHUCKLING] I love this. SURMA: I’m already afraid
of what you’re going to do. JAKE: So let’s take the
actual content of the shell, so it’s there. And the slice point is
going to be content go here because that’s– SURMA: Oh, what? JAKE: Look, it’s there. Look, look, so we’re
going to split on that. SURMA: That’s fine. JAKE: This is web development. This is fine. SURMA: A harmless
comment that I thought was just like to guide
you is actually now going to become a programmatic
instruction of where to split the shell into header
and footer bits because– JAKE: Why not. SURMA: –why
wouldn’t you do that? JAKE: So here we go. We’ve got the shell start, and
so what I’m going to do is– let’s see, shell.slice. And I’m going to take
the shell.index of– and it’s going to be
of that slice point. So that’s actually going to
give us the end, so I want zero there as well. And I should just be able
to copy that end over end and just remove that there. And if everything works,
then we can see that. We got the shell starts. SURMA: Shouldn’t you add
the length of slice point? JAKE: Oh, I knew you
were going to say that. SURMA: Because I don’t want
comments ship to production because it’s a waste of bytes. JAKE: So what Surma’s talking
about is, like in the end there, it’s got this
comment sitting there, so let’s get rid of that. There we go. Plus slice– oh, yeah,
slicepoint.length. And now– SURMA: I feel much better. JAKE: You happy now? SURMA: Yes. JAKE: And we can see
that has sort of updated, and there you go. SURMA: Perfect. JAKE: OK, so now we just
need to cache these. SURMA: Yeah, so we
need to cache them. Then we have them in
the Service Worker, and then we can actually start
stitching things together. JAKE: Absolutely. SURMA: Cool. JAKE: So if we want to add extra
things to cache in the Service Worker, we’re doing
that in roots right now, so I’m going to
continue to do that. So let’s go to shell
start and shell end. There we go. I always like to
just double check that this is actually working. This one has sw.js. And we can see– yes, so we
can see those things there. SURMA: Cool. JAKE: So that’s all working. SURMA: So that means now,
because they’re in that list, they are going to get downloaded
on Service Worker, installed. We have it available to cache. And we can use them to now do– that’s going to be
a weird sentence. We can do the
server-type rendering– JAKE: In the server. Yes. Yes, it’s kind of– Service Worker went– Service
Worker side rendering. SURMA: That’s a thing now. JAKE: That’s a thing now. OK, so this is going to require
a little bit more code over in our Service Worker. The first thing we
want to do is kind of identify those pages
that we’re actually going to do this
streaming thing with. SURMA: Because we
don’t want to put like images in between
our headers and footers. JAKE: Right, and
the easiest way to– and this is one of
the things where things like Service
Worker Toolbox and all of that sort of stuff
come in really handy, but we’re not using them. SURMA: So we are
purposely reinventing the wheel a little bit
because you can’t appreciate the amount of work
these projects do for you until you
have done it yourself. JAKE: Absolutely. So I’ve paused the URL out
here using the URL constructor, which is kind of part of the web
platform and has been for ages. And that will give us access
to all of the different parts of the URL. So what I’m going to
do here is before– we’re going to treat
the rest of this code here as our sort of,
like, general case. That’s how we’re going
to handle everything. SURMA: I always wonder because
when I write Service Worker, I do the same thing. I often do a new URL to get
an actual parsed version. Why is that not part of the API? JAKE: Because Anne
van Kesteren said no. I think it’s more of a– SURMA: I mean, it is
work that can be saved. You don’t need to do it. And then it can be
up to the developer. So I kind of can see that. I just see myself doing it so
often that I was wondering. JAKE: So Anne van Kesteren
wrote the fetch spec. He has a good point,
actually, that all– everywhere else for
the web platform, we only gives the URLs a string
except for window.location or self.location. SURMA: OK, which is a little
bit of a special case, to be honest. JAKE: Yeah. SURMA: So it’s consistency,
and you always have the option to do it yourself anyway. JAKE: Yes, so the first
thing I’m going to do is– like I said, the Service
Worker gets fetch events for requests the page
makes, and that includes requests of origins as well. SURMA: That’s actually
super interesting because you can cache
requests and responses to another origin. You just can’t
inspect them, right? JAKE: Correct, yes. I mean, if the– SURMA: Unless
there’s [? calls. ?] JAKE: –if you made
a calls request, you don’t get extra
visibility in there. SURMA: But let’s be honest,
who uses [? calls? ?] JAKE: Everyone uses
[? calls. ?] It’s brilliant. It’s how the security
of the web works. So I’m doing an origin
check here, so I’m like– SURMA: So everything
that is your origin. JAKE: Yes, and I
can just compare it straight to location.origin. But then I’m going to have
a look at the pathname. So url.pathname,
there we go, and I want to see if this looks
like one of the articles. I’m going to use regex. SURMA: Because you already
had somewhat of a regex in your back end, where we want
like four digits for the year and then some title. JAKE: Yes, so I’m
going to do that. I can never remember wit regex
which way around the symbols are. Is it hat and then dollar? SURMA: Yes, just start and end. JAKE: Start and end? Excellent, because you don’t
want those the other way around or else it never matches. So it starts with a slash,
and then it is as you said. Well, we could we could
say– be specific. It’s four digits. SURMA: Exactly four digits. JAKE: I don’t expect my blog
to be around once we take over to five digits on the Earth. SURMA: Or have blog
posts from pre-year 1000. JAKE: What will the
world be like then? And then the rest of it is just
anything that is not a slash. I love regex. I mean, that’s totally
readable, right? SURMA: Yeah, everybody will
just look at this and be like, I get it. JAKE: I get it, yeah. So if that happens, I’m going
to defer to another function like that’s called
stream article. There we go. I’m going to pass in
the event and the URL. And this is the function we’re
going to write to sort of deal with all of that. SURMA: Basically, that’s
the stitching of the– app shell is the word
I was looking for. JAKE: Yes, absolutely that. We’ve been writing
a bit of code. We haven’t tested it for a
while, so let’s return new. SURMA: As a side note,
Andrew [? Betz. ?] Hi. He asked a question. JAKE: Hi, Andrew. SURMA: “Event.WaitUntil–
when to use it? Any rules of thumb?” And what is your take on that? JAKE: So you use event.WaitUntil
whenever you’re doing asynchronous work,
and this tells– in some cases, the return
value is meaningful. So like an install, if
the promise rejects, then that tells the Service
Worker, this install failed. Something went bad. Either we failed to
cache some things or there was an error
thrown or something, and the browser will see that
as an indication of like, I’m not going use
the Service Worker. SURMA: Which is probably
good because if you have to work on like a broken
basis to bootstrap your page, your installation
should go flawlessly. Otherwise, it’s
better to be like– JAKE. Absolutely. SURMA: –let’s not. JAKE: Yeah, and that’s
another good reason to use unique cache names when
you’re updating because you don’t want to kind of do
half an install and botch it, and you’ve already messed
around with some of the stuff that the current
version’s using. Whereas with activate,
wait until is just a signal that you’re doing work,
and then the browser will prevent fetch
events coming through until you’ve done that work. And fetch also has
event.WaitUntil, which is way to say look,
I’ve sent the response, but hey, I’m doing some
extra work as well. SURMA: And that’s
actually interesting because you can say,
event.RespondWith, and already have your response
ready, and then have to do more work after
the response has already been given out. So try to get to call respond
with as fast and as early as possible to get
that out of the way, so the client, the actual
browser, can continue working. And then continue with updating
the cache or whatever you want to do in the background. JAKE: Absolutely, and we are
going to use that, in a minute as well. SURMA: Oh, cool. JAKE: But first, I just want to
make sure that all of the stuff is working. So start’s there. So I’m going to use a
feature of Service Worker here, of our dev tools,
called Update and Reload. And this is one of my favorites. Because currently
we refresh the page, and then it looks for an
update to the Service Worker. It finds it. It installs it. And then you have
to hit Refresh again to actually get code running
through that new Service Worker. This here means
it shortcuts that. It just takes one refresh. It finds a new Service Worker. SURMA: So usually it
would have to reload. It checks the Service
Worker, downloads, installs, and he has another time
to actually activate while this just throws
away the old Service Worker before the reload,
downloads the new one and, yes, that one
gets installed. JAKE: Absolutely,
so now we should be able to just hit Refresh,
and that new Service Worker comes in. That’s fine. This is what we expect. But if I go to this article,
it says this is an article. Excellent. SURMA: I mean, it’s somewhat
of an overstatement. JAKE: I mean, how much text
do you want in your article? But what that does is it
confirms that we’re correctly identifying that you wrote– SURMA: The root regex,
the cryptic one, is actually correct. JAKE: And we can see
that the includes, it’s not capturing those. It’s just sort the
overall article page. So right, this is
where we want to start doing the actual magic of tying
all of these streams together. So what I’m going to do is
gather all of the parts that we’re going to join together,
so I’m going to do caches.match revGet and static, so the
first thing is the shell start, and mostly I’m using revGet to– SURMA: But the first
thing we want to send back is the header because
we know it’s always going to be the same, and
we know we have it in cache. We don’t even need to worry
about the actual content right now. We can already start
streaming that bit. JAKE: Because that’s the
sort of generic part, so that’s all working fine. And we’re going to
do the end as well. But in between
those two bits, we want to send the
actual content down. So I want to fetch,
and I can’t just fetch the URL here because that
would be for the full article page. All I want to fetch
is that include part. SURMA: Right, and
that is probably where it comes in that you
just put something on the end because you can just
take the request URL and add slash include. JAKE: Well, I’m going to be
a little bit safer than that. SURMA: Ooh, look at you. JAKE: Yeah, well,
because for instance, if there was a query string at
the end– like a search string, as the web platform calls it– just adding include
to the end of there, that could start
breaking things. So you can see here
I’ve done, new URL. URL, that kind of clones it. So I’ve got a copy,
and what I can do here is do pathname plus
equals include, so now that is going to add it
to the end of that URL there. So I can just fetch that,
and that should work. But now this is the part
we want to sort of tie all of those together. SURMA: Yeah, so each of these
responses from the cache and from the network
are, by themselves, individually streaming. But usually, I
remember when I first wrote these kinds
of Service Workers, I would just turn
them into a text blog, concatenate them,
sent them back, and that is not streaming. Because that would mean I would
have to wait for the fetch to finish before I would
start sending the header. JAKE: Right, and if
you do that, you’re going to have that whole problem
where you’re having to buffer the entire response before
anything comes through, and that’s no good. So what I’m going to do is– we want a writable endpoint
that we can sort of feed all three of these
to that will turn it into one readable point. So because in that
with a response, you can give it a readable
stream like this here. SURMA: It’s sort of a string. You’re not passing in, though. JAKE: What I’m
going to do now is I’m going to create a for loop
where we can sort of go around each of those parts. But first I need to
create this readable and this writable
object, and there’s going to be a great
feature in the web platform that can do this for us. So I can do a
readable/writable, and that equals new transform stream. Now, transform
stream is something that’s going to take like
parts, let things in, and chuck something else out, so
changing, transforming the response in some way. But if you don’t provide
any of those details, it just takes stuff
into the writable and pipes it out
of the readable. The bad news is we don’t have
that on the platform yet, so we’re going to have to sort
of hack our way around it. And I’m not going
to write that now. I have a hack prepared. Thank you, [INAUDIBLE]. This is an identity for you. Why didn’t I just do
this for the whole thing? It’s just I have a project here. SURMA: I have a few snippets. I’m just going to
stitch together. See, you learned a lot today? JAKE: Copy/Paste. SURMA: I think it is actually
legit to copy paste in that bit because it is part of
the specified platform just browsers haven’t gotten
around to implement it, or actually, the spec is
not completely finished, as far as I’m aware? JAKE: Yeah, they’re
still working on that, but we think it’s going
to be landed in Chrome in the next few
months, so sometime before the end of
the year, which maybe means it’ll be next year. But we’ll wait and see. What this [? polyfill ?]
is doing here, it’s creating a readable
stream and a writable stream. And we can see here, sort
of inside the writable, when it receives some data, it’s
just passing it to the readable. SURMA: So it’s literally just
like whatever you receive, put it out on the other side. It’s literally a pipe. JAKE: Yes, yes, and
that makes our code like so much easier to
write because now we’re responding with our
readable stream, but we’re not putting
anything into it yet. So this is where we need to
actually start creating that, and so we want to do a little
bit of asynchronous work. So I’ll do event.WaitUntil. SURMA: Oh, I see. I was wondering if you forgot
to make this function async, like you’re actually doing
an anonymous async function inside. JAKE: Yes, and so while we’re
doing all of the streaming work, this is instructing
the browser like, hey, don’t close
the Service Worker. We’ve still got important
things going on. You need to let us handle this. So what I’m going to do is go
through that array that we’ve made all of those parts. SURMA: OK, cool. JAKE: Let’s call it
parts because that would be a better name. So now I got each
of those, and I’m going to get a response
object from each. SURMA: Couldn’t
you use for a wait? JAKE: Yeah, so
that’s interesting. So there’s a new thing appearing
in the platform, which I don’t think we have in Chrome yet. SURMA: Oh, we don’t? Oh, then never mind me. I thought– JAKE: But yeah, you’re right. We could do that, and that
will process the promise. SURMA: So we are iterating
over an array of promises because both caches.match
and fetch return a promise. And with for wait, it wouldn’t–
for would iterate over the array and give
you the promises. For a wait would give you
whatever the promise resolves to, and would waot with the
looping until that promise is currently– that is the next
one has resolved. JAKE: Yes. SURMA: So yeah, I’ll
check if we have it. JAKE: Well, we definitely
don’t have it in Stable, and that’s what I’m using. I wanted to use Canary,
but it turns out that this morning all of the
network throttling and offline stuff is broken in Canary. SURMA: Oh, that’s cool. JAKE: So like a peasant I’ve
had to go back to Chrome Stable. SURMA: Stable. JAKE: I know. It’s terrible. SURMA: What a nuisance. JAKE: OK, so we’ve got
this response now for each of these parts. And what I’m going to
do is response.body, which is the stream
of the response, and I’m going to pipe
it to the writable. SURMA: And so there is your pipe
call that we have seen earlier. In the Node environment,
it’s similar. JAKE: Yes. SURMA: It’s not the same,
but it’s very similar. JAKE: Yeah, so it’s
differentiated in web streams. We have pipe
through and pipe to, which is kind of whether you’re
dealing with a transform stream or whether you’re
dealing with a writable. And I need to wait that because
we’re going to let that happen. And now, by default,
when you pipe something like a readable stream
to a writable stream, once it’s complete, it
closes the writable. It says, I’m done. Now you are done as well. We can all go home. It’s fine. But we don’t want
that to happen here because we want it to write
to all three, all three parts. So there’s an option here
called prevent close. SURMA: To prevent closing,
a very well-named option. JAKE: Lovely, nicely named. But once we’re here, we
actually do want to close it. I mean, you could do
fancy things with the loop where you detect if it’s the
last one and change that. SURMA: Like I could
just do it after. It’s arguably more explicit. JAKE: I think it’s fine. So here I’m going to do a writer
and get a writer from memory. SURMA: Writable,
get writer from– JAKE: Thank you, I knew
that didn’t sound right. So writable get
writer, and this is holding a lock on the stream,
so we can do stuff with it after all the piping’s done. And then I’m just going to call
close, and tell it it is done. SURMA: So that means– yeah, OK. So now that would mean that
the response– no, the writable should consist of the header,
then the content, then the footer. JAKE: Yes. SURMA: And to the
browser, it would look like it is one document. JAKE: Yeah, as far as the
browser’s parser is concerned, it is just receiving
one response. Like, the whole thing
about it being three parts, that is entirely inside
the Service Worker. Now– aha, I just spotted a bug. I’ve still got
transform stream there, so let’s change that
for identity stream. SURMA: Yeah, transform streams
can actually transform. It can hook in code and
do some transformation. Then your stream is like– just whatever you get,
just don’t do anything. Pipe it back out. JAKE: Yes, and the default
for a transform stream will behave like
an identity stream. SURMA: OK, so just to recap,
we are taking the header, which you have in the cache. JAKE: Yes. SURMA: We are taking
the content, which we are fetching live from
the network, which could be a little bit delayed or not. And we are taking the footer
from the cache again, which are three individual responses. And these responses
are now being stitched together so that to
the browser it is one document. But even if the actual
content is delayed, we’re still starting to send the
header straight from the cache. And the good thing about that
is that we would actually see something on screen even
if our network is being weird about sending or has problems
with actually getting it fast enough to have
like a fluid delivery for the whole thing. So I guess at this point
we can actually try and see if this works or not. JAKE: Yeah, that’s
the moment of truth. So let’s have a look. So we’ve got identity stream. We’ve got all of our parts here. It’s all looking correct. SURMA: I mean, if you can
just look at JavaScript and say it’s correct, that is
actually hugely impressive. JAKE: Well, I can’t,
so we should find out. I’ll tell you what
we should do, we need a way to sort of
know if this is working. So in the shell where
it normally says, Jake Archibald wrote, we’re
going to put streamed. SURMA: Whoa. JAKE: So we’re going to
know that that’s working. SURMA: So that
means if we reload the page with our Service
Worker, it will say wrote. If the Service
Worker is actually doing its job in
between, the wrote at the top in the green box
should turn into a streamed. JAKE: And it did. SURMA: Amazing. JAKE: Look at that. That’s amazing. I’m so glad that worked. Oh, OK. There’s a problem. Has your eagle eye spotted it? SURMA: I have seen the problem. JAKE: The problem? So what we can
say here is like– SURMA: What used to be Unicode– JAKE: What used to
Unicode is now not. Yeah, OK, so this is a problem. SURMA: Sounds like you stripped
a little too many of the meta headers maybe. JAKE: That is exactly it. The response here, there’s
no response headers at all being sent. What we really
want is something– what I just did there is a Shift
Reload, a Command-Shift Reload. SURMA: Yeah, that passes
the Service Worker. It goes straight to the network. It bypasses, not
just passes it– bypasses the Service Worker. JAKE: So what I can do here
is have a look at this. This is the content
type header I’m normally sending, so I’m going to like– SURMA: I mean, you could
also put it in your header and say meta char
set UTF-8, right? JAKE: Yes, I could do
that, but you know, I’m doing it on the server side. Why we wouldn’t I? SURMA: It’s fine, Jake. JAKE: But it’s seems good
to have some proper headers. Right now, we’re not even
telling it it’s HTML. It’s just coincidence. That’s what the browser
will interpret it as. So here I’m just going to do
content type and there we go. And what should
happen, so if I– I’m going to keep
the update on reload. SURMA: Yeah, so we’re going
to get the new Service Worker straight away. JAKE: So we should see it
straight away, and we do. SURMA: It’s streaming. We have the right
content encoding. So we just built a streaming
Service Worker, didn’t we? JAKE: Yes, we did. SURMA: Or you did? JAKE: Yes, we did. It’s yeah– and I think
that’s all we need to do. Oh, there’s one thing
that we need to fix. And this is a problem I think
we need a better solution for in the web platform. And that’s that we’ve got this– it’s still says loading up
here, as the title for the page. SURMA: True. Oh, a changing title
that used to be all the rage in
the ’90s, we would have like little
animations going on. JAKE: And that is the solution
that we’re going to use here. So it’s just here in the
article include, and I’m just going to do a script. SURMA: Oh, that is amazing, JAKE: It’s horrible and hackey. It would be nice if we could
have multiple title elements, and that one would
replace the other, and it would sort
of update, you know, with whatever the last
title element it sees is. But what I can do here is
just let’s go for meta.titles. This is coming from the
scripting, the templating engine– and JakeArchibold.com. And so now, there,
it’s updating. SURMA: Nice. I just got a question. “Is there anything
like incremental cache update like diffing or
something like that?” JAKE: There is not. But it’s something that
you could build yourself inside the Service Worker. So you could be sort of
fetching stuff that you could, you know– you tell the server, I have
this version of this asset, or it has this
hash, or whatever. And then the server
can go, oh, yeah, I know the history
of all of this stuff. Here is just a diff to apply. Whether that’s
something that’s going to be useful in the long term– SURMA: Yeah, I don’t know. So just as the
final proof of this, can you do this with
networks throttling so we can see that the
shell appears right away, but the content
gets streamed in? JAKE: I thought you’d never ask. And I think that’s kind of
what we should end on and have a look at what the
app shell compares to with this, the idea of
using it with JavaScript. So let’s put the throttling
all the way down to GPRS because you know
it makes it look– SURMA: The slowest
of the slowest. JAKE: Well, is offline slower,
or is that just broken? SURMA: Is nothing
still something? Who knows? Now we are getting too
philosophical in here, I think. JAKE: So I’ve turned
update on reload off, so it’s not going to try
and initiate Service Worker. And I should just be
able to reload the page. SURMA: So you can see– that was actually
really cool to see. And if you didn’t– did you have
screenshots enabled? JAKE: Screenshots are enabled. SURMA: OK, so we can
revisit what we just saw, namely that I think, in a matter
of a fraction of a second, we had something on screen– namely, the shell like straight
away from the [INAUDIBLE].. Here is the header. JAKE: So we can
have a look here, and you can see that– so
here’s the sort of paint time. I have shifting. So kind of 65 milliseconds,
we got that first paint of that topic of content. And if we move along to– where is the next paint
server, around here, so that is at one second. That’s when we actually start
getting the article content. And that’s coming
from the network. And that’s the bit
that’s being throttled. And so that’s, you know– so I’m going to rely on you
to remember those numbers. So it’s about one
second for content. SURMA: I have an entire audience
to remember this for me. JAKE: Oh, excellent. OK, so if everyone
could remember that stuff, what
I’m great to do is I’m going to see if I can
remember get because you see I’ve done a lot of coding now. SURMA: You made a good stash. JAKE: So I’m going to get that. Would that work? Would that be also
files that haven’t been added to the index? I don’t know. Let’s do this. SURMA: I think you
might be right. JAKE: So I’m just
going to call this– SURMA: Attempt commit,
because why wouldn’t you? JAKE: Why not? Oh, yeah, and it
added my name already. SURMA: That’s fine. JAKE: So now I’m going to
do checkout and app shell. Excellent. That’s worked now. The server’s restarted. So let’s refresh the page. So this is now just– I should turn the
throttling off because it’s let it update that
Service Worker, so we should see that there. That’s fine. So if I refresh the
page, it says, I app shelled some content. Excellent. So that’s the proof there
that it’s actually changed. So now we can compare this. So the difference here is
it’s loading in the shell all at once, and then it’s going
to– the JavaScript is going to pick up all the content
from the same include, and then it’s going to
insert it into the page. SURMA: So we should compare
this obviously to this over the same network speed. Otherwise, it wouldn’t
be a fair comparison. JAKE: Absolutely, so
we’ve got GPRS on again, all of the same sort
of cache settings, and we can load it now. So, yeah. SURMA: You can already
see the difference. There was enough time for
us to look up to the camera and look confused why we’re
looking at an empty app shell. And it’s still going. So if you have some
kind of single page app, this kind of streaming
Service Worker can make the experience
of opening and loading a site so much better. JAKE: So we see we
got the first render. Yeah, that was still quick,
but the final render there was kind of like three seconds? SURMA: Three, four
seconds in, which is– and this is obviously not
a full blog post, I think. It’s just some text. If you have a longer
blog post with some media assets or whatever,
it can get worse. JAKE: Absolutely, some
of the longer articles I got on this, it
goes up to like eight seconds whereas the streaming
one is always there kind of pretty much straight away. And it’s also slower because
you dump all of that HTML like right at the end. That is the point it
discovers all of the images and stuff it needs. So those downloads
start much later. SURMA: Are also delayed, so it
is basically a win all around. So I mean, that is
how you do, I guess, a streaming Service Worker. And just to be clear, it’s
actually kind of cool. You just did that in Stable. Usually, we are very prone to
being on Canary with the web platform flag enabled and doing
all the bleeding edge stuff, but this works in Chrome Stable. And it actually works
in Firefox as well? JAKE: Unfortunately not. They don’t have streams yet. SURMA: They don’t
have streams yet. JAKE: That’s their
blocking thing. SURMA: Safari doesn’t
have Service Worker. JAKE: Yes, Safari
does have streams. SURMA: But they have streams. JAKE: Yes, so if they could
just exchange some code. SURMA: Yeah, talk to them
and be like, oh, you want– can’t we just– soon, I hope, we
will be on a platform where everybody has
Service Worker and streams, and we can do these kind
of performance tricks much more often. So as I said, we’re
going to put– this piece of code
that Jake wrote, we’re going to put up on
our GitHub repository. Thank you so much, everyone
who came by, and talked to us in the chat,
and asked questions. I hope you learned something. And thank you, Jake, for
taking on the challenge. I think you did amazing. JAKE: Thank you. SURMA: And with that,
have a good Thursday and see you next time. JAKE: Bye bye. [MUSIC PLAYING]

11 COMMENTS

    Chapters:
    0:09 – Intro & talking through the existing setup.
    9:30 – Creating & registering a service worker that logs to console.
    15:19 – Writing a fetch event with a very basic offline fallback.
    18:12 – Caching HTML, CSS and images, then modifying the fetch listener to create a branded offline page. Includes using static-module to dynamically write JavaScript.
    36:28 – Auto versioning caches.
    42:25 – Deleting caches from previous versions using the "activate" event.
    45:11 – Talking about app shell vs streaming when it comes to speeding up page loads.
    47:25 – Creating an endpoint that serves the middle of an article.
    50:15 – Creating & caching a generic page start & end.
    54:45 – Handling particular routes differently in the fetch event.
    1:01:08 – Combining three responses into a single streaming response.
    1:11:18 – Uh oh encoding issues.
    1:12:56 – Fixing the page title.
    1:14:25 – Showing the performance difference vs app shell.

    45:10 I don't think that using promises or async functions necessary defers work. Depending on the task and the underlying hardware they can get resolved in the same frame. I think the only reason they are useful, is that they don't block the event loop, as Jake said. But please correct me if I'm wrong.

    This is the my first time using the Cache interface and I have a question about the about this "caches" object that maybe someone here might know the answer of. Why does this exist? Isn't this exactly the same as "CacheStorage"? Why is "caches" preferred over using "CacheStorage"?

Leave a Reply

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