Building a Media Player #5: The Server-side Node.js Code

Building a Media Player #5: The Server-side Node.js Code

PAUL LEWIS: Hello, and welcome to yet another developer diary So to this point, I've shown prototypes and explained a little bit of theory

But finally– finally, but finally, we actually get on to talking about what's been going on in the actual application code And in this entry, I think I'm going to mostly concentrate on the server side So firstly, I suppose I need to acknowledge that a lot of this code really came from Surma If you've not seen our Supercharged episode where he talked about server side rendering, definitely watch that It was a live stream where he took about an hour or so and built a relatively straightforward, Handlebars-based, Express-based, with caching headers, server side rendering thingy setup

And I guess, yeah, a lot of this is– the ideas, anyway– have been picked up from there about how to do some of the caching and so on And it was also Surma who told me about Express sub-apps or Express apps, that you can actually have lots of them But more of that in a moment because, well, there's code to look at So let's have a dive in and see what's there So this is actually the server as it runs today, which largely involves getting a copy of Express, making an app to wrap everything else

And I'm running all my stuff on the flex containers in Google's app engine So what you can do there is you can boot up a container which runs Node It's great It's like that And then it wraps it in the auto scaling, load balancing stuff

It's really quite handy for a lot of this But it patches in the port as part of the environment variable So we basically pick that up And that's what we run on, whatever it tells us to run on Beyond that, there's some middleware

And I'll come back to some of this in a moment I have also got passport enabled, which is a way to do a [INAUDIBLE] if you need to do it And I'm not sure if I'm going to or not, whether I'll have an admin area or whether I'll have a place where people can actually log in so they can see their own– what they've rated or whatever I'm not sure yet But I've put it in here just for now in case I need it

But the interesting ones actually kick in below So there is an app here for static So anything that begins /static, I hand off to this app, which is under Apps, Statics Let me have a quick look under there And this is actually relatively straightforward, this one

It's basically going to call expressstatic with a path and the ops And the ops is that we want anything that comes from /static to have an age of one year on it So it will expire in one year, not a moment sooner, apparently But that's the idea

We're going to say anything that begins /static, grab it from there In this case, it actually goes to the Client folder, which is up here, and grabs it from there We'll come back to that, I suspect, in a little bit So anything that begins /static, which is images, the manifest, so on and so forth, go and grab those from there The authentication one– I'm not going to get into that right now

That's the stuff that would use Passport Because I'm not sure if it's actually going to survive, if I actually need it or not, there isn't a lot of point in me showing that just yet If I do do anything that requires it, I'll come back and explain that It's mostly placeholder, which is the same with the admin It's just me testing the auth stuff

I'll tell you what We'll jump over the service worker one, and we'll come back to it in a bit Most of the app is actually served through this dynamic one, this dynamic app So let me show you around that a little bit So this is not dissimilar to the static one, except it's way, way bigger

It's its own Express app, which I call Dynamic I'm using Adaro Adaro? This is the problem with reading names online You never know how to pronounce them And then you have to say them out loud

And there's a good chance that you're going to look like an idiot I don't need much help to look like an idiot, just so you know Glad we had this chat Anyway, I'm using– I'm going to say Adaro, I think And if it's wrong, oh, well

And what that does is it wraps Dust JS So Dust JS is an alternative to Handlebars or Dot JS– any of those, really I wanted to give it a go because it supports promises and streams, as I understand it, so that you can– in theory, at least, if you want to– make your templates– build them async So if you need to do something which requires a little bit of async work, then you're not blocking forever while that happens All the same, it seemed like an interesting thing to go and play with

So that's what I'm doing In order to make it work in Node, though, you need to wrap it around Dust JS And that's what Adaro is Then we have a bunch of setup stuff, really, which gets me things that I need about reading my video library, information about the videos that I've got, information about the actual package itself Because I use things like the version number in the package JSON to stamp certain files to make sure that that all works

I have a bunch of helpers, which again, we can come back to, which are– they're helpers that help me with the templates that Dust JS is going to create Finally, we have a little bit of setup here for the actual default view, like what the title is going to be, the page, what scripts we need, and so on Then we step into the actual config of the engine, where we can say create dust engine, set up the views to use the view path, and also, anything that comes from the dynamic side is going to be HTML And therefore, I don't want it to cache at all So if you remember the stuff in /static, it had a one-year expiry

The stuff from dynamic, I want it to expire immediately I never want it to be cached Because what we're going to do– I call it cache and hash You could do cache and grab, hash and grab, cache and hash and grab, any of the above, whatever you like But I call it caching and hashing

And this is something that I definitely got from Surma So we'll talk about that more in a moment But the idea is, first of all, anything that's HTML, don't cache that Anything that is from /static, definitely cache that, and cache it for a year Right

So let's talk about– this is one of the roots in the home page We grab the Default View Options We add in the things that we need to add specifically for that view like, which is the featured video, which are the newest video, any things that we want in lines, like the JavaScript and the CSS, any particular scripts that we want to add to that And then we finally just call render against it with the template that we've got, which is home

And that's it It will basically render that out and send that back to the client Works just great OK, let's talk more about the cache and hash stuff The idea is that if you have an HTML file with paths to, say, the manifest or the JavaScript or the CSS, and any of those change, you need to flag that to the browser

Because you've said anything that comes from /static, like your JavaScript, like your CSS, like your manifest, they should be cached for a year So what you need to do is you need to do something probably to the file name That's what most of us do We put a revision into the file name so that you can cache that revision for a year But if I change the HTML, or if I change the files, the HTML will get a new revision in there for that particular file

So let me show you what I actually mean Let me bring up the browser Wrong browser Let me switch across to the correct browser So I'm running the site on 8080 at the moment

Ta-da And let me show you Here's a great one here Yeah, this is ideal, the manifest here You can see that we've got this– manifest dot, and then this long string here, dot JSON

Well, how are we doing that? Let me show you here This is one of the middlewares that I mentioned earlier Or is it helper? It's a helper Sorry It's one of the helpers, which we've registered up here, this one here, the hash helper

What it does is it gets handed a path And what it does is it opens up that file You can see here, load the file contents And then it creates a hash from the file contents by making a SHA-256, writing the file data in there, and asking for a hex dump out the other side, which is 64 hexadecimal digits long And we use that, and we replace the file name

So if it was– you can see here Let me actually bring– let me grab– let me show you this In the header, there we are This is what it actually looks like So I said, look, get the dist client manifest

json And it will grab that file, look at the file contents, create the hash for that And then it will spit back out an updated path that looks like this, all that There we are Now, that's good, and it's bad

It's good because that means this is unique So when the manifest changes, this hash will also change Brilliant But it's also on /static, which means that it will be cached for a year So that's all good

The only thing now is when we actually make the request, this file doesn't actually exist in /static I mean, /staticmanifestjson exists But manifest dot all that dot JSON doesn't exist So what we have on the other side is a little bit of middleware that just simply removes the hash

If it gets given a request that has 64 hexadecimal characters right next to one another, A to F, 0 to 9, then it replaces those with an empty string, and then passes straight through So it's a completely silent bit of middleware that just says if you get a URL with that long hexadecimal string, remove it And we'll now ask for /static/manifestjson, which means when we come back to the server, we've asked for the file We're going to get whatever the server has as the most recent value

So that's a way of keeping that all up to date Last little bit I'm going to show you on the server side today is around what I've been thinking and what I've been doing to do with the service worker There was– there was a service worker app that was dedicated just to the service worker Fairly similar, in some ways, to the dynamic 1 But all it does is it totally controls the service worker only

That's the only thing that it's actually interested in So not dissimilar in terms of setup We've got all the Adaro stuff, and we've got default dust options here, and so on But what we do is– you see that I've got this package reader, getversion

And all that's doing is it's opening up the package JSON, which is– it's currently set to 100 And inside here– inside– well, I lost it There it is

Inside here, you can see that I render this service worker template, and I pass through version So when we look over here at– I believe it's over here Nope That's the built version, I think Oh, no, it's here

You can see that we have the curly braces version So that means that if I want to bump the version of the whole site, and I want to invalidate my service worker, I can do that just fine Because what I'll do is I'll bump the version in the packageJSON And I'll deploy a new version

And then on the server side, we'll generate a new– well, that version number will be passed through to the service worker So when we next request the service worker, we'll get 101, for example That'll be byte different to 1

00 And then we'll run the whole install activate process So my means– I've used it before a bunch of times now I did it in Chrome Dev Summit

I've done it in– I think it was Voice Memos I did it in, possibly even Guitar Tuner as well A bunch of the stuff that I've built is really convenient to just go, bump the package version, and then send that out And that will cause your service worker stuff to be updated And the other thing that it also does, or it should do– yes, it does– is it makes sure that my service worker is never cached This is a super important thing

Even though, technically, I guess, this might– no, it doesn't live in static But even if Express wanted to cache the service worker for a day or a week, we really don't want that Service workers, you really want them to cache for no amount of time And the reason is we want to be sure that if we update our service worker, that we definitely come back– the people who are connected to us definitely come back and get it As it happens, even if you set a service worker to cache for more than a day, the browser will always come back after one day

I believe that's in the spec It does mean, though, that if you set the caching headers to be like a year, you're going to have to wait at least a day before any changes you make to the service worker get passed down to anybody who's already got it installed So strong recommendation for you there– make sure that your service worker has some kind of no caching headers, very much like the HTML, so that if you make a change, it can get deployed instantly, as in as soon as somebody hits your site, they'll go, oh, I need to get a new service worker And if they can, they'll download and activate and install, and all the rest of it, your new service worker So there you go

All the code, as I mentioned previously, is up on GitHub I will link to it in the notes below So that's the service side of things Next up, I think we should have a little bit of a chat about maybe more video stuff Because that is what we're building

Don't forget, you can subscribe to the channel Don't forget, you can leave comments below Loving reading all the comments Thank you so much for all of those It really does make all this worthwhile because it's so nice to see what you think and also to get your questions as well

So if you've got questions, definitely pop those in And I'll try to either respond to them in line or in the next video that I record Too-da-loo Hey, folks Thanks for watching

Don't forget that there is more content that you can find kind of over here-ish And if you want to subscribe, there's probably a button– I don't know, maybe there, maybe somewhere around there Click that if you've not done not that Brilliant