Server-Side Rendering: Live Code Session - Supercharged

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
SURMA: Hello, and welcome to the Supercharged Livestream. I'm Surma. JAKE: And I'm Jake. SURMA: And today we're going to Server-side-- JAKE: Service workers. See, Paul couldn't make it into the office because of the British train system, so I thought we could have a whole episode entirely devoted to service workers. PAUL: Hey, I made it, I made it. What are you doing here? JAKE: Oh, because you were late, I thought we could do this entire thing all about service workers. PAUL: No, you can't do this, you keep trying to take over. Can we have one thing around here that is not about you and service workers? JAKE: OK, show of hands. Who wants this episode to be about service workers? Fine. PAUL: Well, that's rid of him, then. So sorry about the tardiness on the show in the [INAUDIBLE] front. Yes, so what we doing? SURMA: We are actually going to do sever side rendering. And we're going to do it with you and not with Jake. There was a lot of confusion on Twitter. Was actually very enjoyable. PAUL: Whoops. Yeah, anyway, I did make it, and that's fine. I'm not doing the coding today, you're doing the coding. Yeah, it's a bit of a switch around. I'm going to be on hand to answer questions and talk to the folks, and I can already see we got lots of comments coming in. SURMA: Loads of people already. PAUL: So hello to everybody in the chat. Thank you for joining us. We love to have you here, so do feel free to keep chatting away. SURMA: And you can make Paul interrupt me so that I do more mistakes. PAUL: Yes! SURMA: My goal for today is try to do less typos than you do, and I'm pretty sure I'm going to fail. Although you do set the bar pretty high. PAUL: But this is my revenge. I mean, I'm going to be very supportive throughout. SURMA: Server-side rendering. PAUL: Server-side rendering. OK, what are you doing? SURMA: Server-side rendering. Yeah, I should probably explain, because this word has been-- or those three words. Two words if you're using a hyphen. PAUL: Just those words. SURMA: Have been thrown around a lot. And I feel like there's not a very consistent understanding of what it actually means, and so I'm trying to capture it in a few words. Server-side rendering is what you want to do if you have a single page app. If you think back to the first router that we did, we actually used a little pipe [INAUDIBLE], I think you wrote that whatever you request, you would get back the index HTML. So if we requested slash about, or just home, or slash contact, you would always get the same index HTML. Which means in that site there wouldn't be the content that you actually wanted to read. So you would have to wait for the JavaScript to spin up, to analyze the path that has been requested, and swatch swap out the content in the Dom with the actual content. PAUL: And then we switched it up to the advanced router, which did actually have individual pages for like about, contacts, misc, whatever it was. And then we pulled those in over-- SURMA: But that would mean that whenever you change something in the layout that you would have to do the edits in all of these individual pages. PAUL: Right. So presumably what we're trying to figure today. SURMA: Server-side running basically still is always deliver the index HTML, but already inject the content before serving it to the user. So you render the Dom on the server side, that is why it's called this way, and send it to the users so that content's already there without the JavaScript needing to run at all. And then hydration happens, where the JavaScript spins up and takes care of all the dynamic parts. PAUL: Go, go, go. SURMA: So, let's get our hands dirty and write some code. So we're going to write note on the back end. We're going to write a Note web server that does the server-side rendering. So I'm going to make the script with copyright headers so that we can run JavaScript just with executing the script. So in the folder here I have an app folder where basically our advanced router code is in, the thing that we wrote two sessions ago, I think? It's exactly the same, not much anything has been done. And for this one I decided that I want to use Express. Express is just a little bit of convenience about Note's native web server, so that we have a simple web server. And you use it by creating an Express app. And this app object is really going to do all the routes. PAUL: So you going to MPN install? SURMA: Yeah, I have the modules in here with Express, and all the other things I plan to be using. I'll explain as I go along what I'm actually using. So we want to start with something simple, we're just going to write a website that it's just a straight web server. It does nothing else. So what we can do there is we want to say that our app uses the middleware that is called static. So what this line does, it just says to Express, just serve the app folder as static content. [INAUDIBLE] set up web server. And then we're going to use Note's HTTP server, create server that serves our app. And we make it listen on 8080. PAUL: Have you got this all committed in your head? SURMA: Well, that is what Note excels at, right? Very simple code that you can-- PAUL: Well, bravo. Well done, it's very good. SURMA: So let's do this. PAUL: Who doesn't love a bit of chmodding? SURMA: Chmodding. PAUL: Plus X, that makes it executable, right? Because you added that line to the top so that it's actually a thing that can run? SURMA: Then if I do this, hopefully-- Nope. PAUL: Can't find module Express. SURMA: Well that's good. It's in there though, right? No, it's not. That's like the only module I forgot to install. So let's do some good old NPM install. PAUL: Oh, that we have to do the install dance while we wait for it to go. [HUMMING] SURMA: But Express install is already done, because Express is not that big. PAUL: Oh, I was only part way through the install dance. SURMA: He does have a very elaborate install dance. PAUL: Fine. So we got a question here. Why not use import express from Express? Why are you doing the old require that rather than anything newer? SURMA: So the thing is that modules, for me, are still a little bit iffy. It's just something, especially on the NPM side, it doesn't feel as right. I'm not even sure if Note 4, which is what I'm using, already supports the import syntax. I'm not sure if we would need an enable in between, I don't know. And also, imports are declarative and not imperative. And sometimes, you do want to have, like I did here, you do want to have the imperative way. PAUL: OK, like grab this thing, and then do this thing. SURMA: Exactly. So for now I'm just sticking to require until the entire JavaScript ecosystem sorts out how to do modules. That's just for me to keep me sane. So. PAUL: Well that's a start, it's actually working. SURMA: There's no error, at least. That's good. So if you go to a local host, there it is. Oh, this is actually a little bit crammed. PAUL: Can you do the-- oh, there we go. I can feel the tension as you're trying to-- don't, get it right! OK. I like how you've selected them all as well, by accident. It feels good. SURMA: So I want to see the protocols roll. PAUL: Ah, that ruined it. Why don't you just make [INAUDIBLE] a bit bigger, dude? SURMA: Oh, I could. PAUL: Hate to be 1.1. OK, there you go. SURMA: So we got this. And now what I want it to do is I want it to port this to HB2. Because, you know, this is the future and we should do this. But for that, we need TLF certificates. So because I forgot to download it, I will go to Google Chrome simple HB2 server. Because not only is it a simple HB2 server, but it will also allow us to generate certificates. So I'm just going to download the Darwin version. PAUL: Is that going to go to your-- SURMA: Which should be here. There we go. And then you can download simple, boom, boom. And now we have a certificate, which we can use. And I'm going to show you how exactly. PAUL: So if anybody has not seen this before, you built like the Python simple server, but it's the built and go. And it's an HTTP2 server, so it has to be running on HTTPS. So you get a self-signed certificate that it makes for you. And then you're basically, wherever you run it from, whichever folder you run it from, treat that as the folder that you're serving from. SURMA: Exactly. And I just use it for the ability generate a certificate. Because using the open s all command line tools is so painful, which is the original motivation to write simple HB2 server, to not have to do that manually anymore. PAUL: So what you're using it for, you want the certificate, so now you're going to use them here. SURMA: Exactly. So what we can do exactly is that we are going to use require FS, and do FS read file sync. We're going to do synchronous, because I'm dirty like that. And we're going to use the key and the cert, read file sync cert.pem. And now what we should be able to do is just to turn over to HTTPS and add the options parameter to our create server, and now it should actually be HTTPS so let's try that. No, error, that's good. We can close this. Let's add this. PAUL: So we get this, which is basically, because it's a self-signed certificate, Chrome is going to say-- SURMA: It's not actually secure. It is secure in terms of encryption, but not authenticity. It can't be sure that we're actually talking to the right server. But since you're on a local host, we have the option to say, you know, I know what I'm doing, let's proceed. And as you can see, we have HTTPS with a red flag, because it's not authentic, but it works. PAUL: So now we're still serving on HTTP1, is that right? SURMA: Yes, because I just switched to HTTPS. Now ideally, what I would like to do is using HTTP2. However, Express currently doesn't work with the HTTP module, because the HTTP2 and PM module is still very much in development. What we can use, however, is the speedy module. Which, interestingly enough, does actually serve HTTP2, you just don't have the option to push. So it is a valid HTTP server. And since you're not going to be pushing today-- oh, I have to restart. [PANTING] PAUL: It's just going to work like this. SURMA: Actually, no it isn't. Did I save? Let's restart it just to make sure. Hm, this is interesting. Options, worked on TOS. Let's just give HTTP2 a try, just to-- I'm not sure I have it installed, actually. I have it installed, apparently. Let's try it. PAUL: Oh, something very strange is going on, isn't it? SURMA: This is already strange. PAUL: Why don'y you try a different port entirely? SURMA: Yeah, let's try a different port. Let's try 8081. Let's restart that, go to here. PAUL: Oh, interesting. SURMA: That is interesting. PAUL: So the question is, why do we not get HTTP2? SURMA: So we are reading the certificate. I mean, there's not much code that I could do something wrong here, honestly. PAUL: No, there isn't. SURMA: I'm passing in the options, I'm passing in the app. PAUL: Hey, well, do you know what? I feel better that it's not just me that has the bugs. SURMA: This is what I expected, I expected us to-- I am also in the right folder, right? PAUL: As far as I can see. SURMA: Yeah, there's speedy, everything. And at the very least, it should be speedy. See what I did there? Should be speedy. Anyway. PAUL: Should be speedy. SURMA: I'm just going to skip over this for now. PAUL: OK, we'll come back to it. SURMA: We'll probably get back to it. So let's take with HTTP1. PAUL: Somebody's suggesting it might be the caching. SURMA: I did do a hard refresh. PAUL: Yeah, I saw you do that, too. SURMA: Oh, that's because I have to-- PAUL: Do you go back to 8080? SURMA: Oh, that's because I still have the options in there. Actually, that's let's stay with HTTPS just to-- PAUL: Make life. SURMA: Let's start the server again. Put the HTTPS back in there. This is working. Let's stick with this. PAUL: Yeah. Somebody said restart the browser. I like this. People are basically saying, switch it off, then on again. SURMA: You know what, I'm going to give this a try. PAUL: And I like the people, I mean, we all like to do that. SURMA: I'm going to restart the server. I'm going to kill this. I'm going to restart Chrome, open dev tools on the Network tab, and go to HTTPS local host 8081. PAUL: No, it really doesn't like it. SURMA: OK, well, let's just keep going. So right now what we're doing, this should all be working. We can go to different subsections, and it loads because we're just doing a static server. What we actually want to do, though, is we want to add special handling whenever an HTML file is requested, because this is where we do our server-side rendering. So what we're going to use is app.get, saying whenever there's a get request for. And now we're going to use regular expressions, so don't hurt yourself. I'm going to try to make this understandable. So what we want to do is-- PAUL: Why do you have the I on the end there? SURMA: Because it's case insensitive. I like case insensitive. PAUL: Sorry, I'm going to be that person. SURMA: I've noticed. PAUL: Yeah, because reading somebody else's regular expressions is-- SURMA: It can be very painful. PAUL: It can. SURMA: And this is probably not going to be pretty. Also, because I'm just talking about this, this is all production code. It's not going to end up being a production ready web server or production ready backend. I'm not going to pay a lot of attention to doing, like, I/O optimizations, or to do very efficient server-side catching, or these kind of things. This is mostly to show how to implement server-side rendering. It's about a technique, not about a specific high performance implementation in this regard. PAUL: Yeah. SURMA: Although we're going to have performance in mind, because this is why we're doing this, and this is Supercharged. PAUL: Yes, it is what we do. SURMA: All right, so let's think about this. When do we actually want to handle a request? That is either when the path is being requested ends with a slash, or-- which is the or for expression-- if it has a slash, something that is not a slash with a slash at the end. PAUL: That right? SURMA: Or index.html, right? PAUL: Wow. That's already tremendously readable. So what we're going for here is, so you could ask for, like, slash home. SURMA: Just /, /home/-- PAUL: Or /home/index.html/ OK, so that's what we're trying to capture. So if you come up with any of those three, otherwise we're going to fall through to the static. SURMA: Exactly. So all the flags that are there are going to be served just as we know. And this is why I love mode 4, because we have function. So what I'm going to do for now is I'm just going to check that it's actually working, and just send back a test string. Hi. PAUL: Could've been on brand, but whatever. OK, fine. SURMA: OK, so I'm going to use supercharged hi. Let's restart the server, I hope. No syntax error, which is good. So if we just go here, supercharged hi. If you're going to go to About, supercharged hi. If I go to about index.html, supercharged hi. PAUL: And then presumably if we do like-- SURMA: Static, what do we have? We have app, we have static, app.js. Jass PAUL: So this should now fall through-- OK, so that's the static hosting that we had before. SURMA: Also, I wanted to show the staic middleware, Express is really nice because in the response they take care of doing sensible defaults like default cache control, default adding an e-tag, doing the last modified stuff. PAUL: So let's talk about this very briefly, because I know this is a bit of a hidden gem, I suppose. When you understand about these headers, life can be a lot more straightforward. I have seen people, for example, using a service worker, and then trying to, like, cache bust, and do all sorts of things. Because they're fighting with their headers. SURMA: Exactly. Which sometimes is OK, because for example, in the pages, you don't have any control over the headers that they use so you might have to resort to these things. But usually, if you have any control over your backend which, for example, on S3 hosting you do, fix your headers. Because caching is part of HTTP and the entire ecosystem, so good caching headers over so much. So at least give yourself proper e-tags so that caching works for your clients and you reduce bandwidth that they use on your website. PAUL: So somebody is basically saying here that e-tags, they've never really understood what the point is. So why don't we take a moment to explain what e-tags are? SURMA: E-tags are pretty great. Basically what they mean is that when you receive a document from a server, it gets an e-tag. And that e-tag is a guarantee that it will only change if the contents of the files have changed. Which is why most server implementations use some kind of checksum, like sha1 or sha2, or MD5, whatever, to generate these e-tags. What the client can then do, put these files into its cache. And when the user goes back and requests the same file somewhere in the future, it can put an if non match header in the request and add the e-tag so the server knows which version the user has available locally. And if the service sees, hey, I have the same version here that the user already has, the server responds with a three or four, meaning not modified, and you save the user re-downloading the entire contents. And this is actually kind of neat, there's also weak e-tags. PAUL: So you file this, it begins with a w/ That stands for weak e-tag. SURMA: Which is defined as the e-tag only changes if the semantics of the documents change, but they're not necessarily byte equivalent. PAUL: What does that even mean? SURMA: Exactly. I have never encountered them in the wild. Express uses them by default. PAUL: But it still does byte different e-tags. SURMA: I guess. So what it means basically is they only have an effect if you're not doing range requests. Because they're not byte equivalent necessarily, you can't do range requests, or use a part of it for a cache. But as long as it's the whole document, you can use the one you have if the e-tags are equivalent. I wouldn't worry about it too much, we're going to cover our own e-tags later. PAUL: Ooh, how exciting. SURMA: Exciting indeed. So we are now in control of delivering our own HTML calls. PAUL: Before you go any further, if you've just joined us, we are doing some server-side rendering today. We are taking the advanced routing that we did a few episodes ago, and instead of having a completely static setup for the HTML files, we're actually building them on the fly in the server. Surma has got some JavaScript code up and running, which is just at the moment sending out some HTTPS basically. And somebody remarks that you have managed to create a regular expression that worked the first time around, which is impressive. And I would agree. I watched you type that out. I was like, I mean, that's unintelligible, I'll grant you that. Look at that in a few weeks, and you'll be absolutely terrified. But all the same, well done. So basically, we got this situation now where if we have a requested slash, slash section slash-- as in /home/, or /home/index.html, we will serve via this chunk of code in the middle. And then everything else is going to fall through to our static hosting. SURMA: Exactly. Because also in Express, the order in which you declare your handlers for the steps is important, because Express goes to through them from top to bottom. All right, so now we have a handler that we have to implement. And the reason I did this is because let's look at our index.html, the original one, which you might remember or you might not. The thing is that between this index.html, the index.html in /about, the one in /contact, they're all pretty much the same except in the SC view element that we wrote. The actual, for example, this one, Home has contents while the other ones are declared as remote because we're not on the page right now. But everything above and below is the same for all pages. So let's split those apart, and this is exactly what I'm going to do. So this one is what I'm going to call the header. Let's expand so people can see where I'm actually going. Server-side rendering app. And this is going to be the header.partial.html. And let's go to the rest and call this the-- oh come on, don't always throw me out of the folder, there we go. The footer.partial.html. So now we have split the file in header and footer, and the actual index.html will not contain much more than this. And I will add something here, which I'll explain later. All right. So the actual index.html, which just half of the content as relevant for this page, is just one line in this case, because it's just one element. I already prepared this for the other sub pages. So the about intex.html also has just one line. Same for contact, just the content for the actual subsection. And the rest has been split apart in header and footer. And what we're going to do now is we're basically going to assemble the header, the actual content, and the footer in our handler. And I'm going to introduce something new, which is we have been using the Note file system order to read files. But the thing is that Note currently-- and they said they won't do this any time soon in the future-- they don't use promises. And reading multiple files with a callback based API makes my head explode. And that's why there is a module called Modernize, or MZ, which has wrappers around all these basic APIs from Note and turns them into promise based APIs. So we can do now basically is we can do promise.all. PAUL: OK, so you're you doing three requests, then. One for the header? SURMA: Exactly. So I'm going to do app/header.partial.html. I'm going to do-- PAUL: This is really depressing, you're not making typos! Oh, fine, carry on. SURMA: And now we're going to need something here, which we're going to talk about in a second, which is index.html. The actual content of the section we want to load. And we're going to read the app-- see, I had a typo. PAUL: Yay. I think this it was just a pity typo, wasn't it? SURMA: Maybe. So we have to sort out what we're actually loading. And this is where the regex comes in, because I have put parentheses about the thing that will be the section that we want to load. And Express, being a nice guy, we can actually go and say the item that you want to load is-- I think it's this? Let's check this. Let's just send back our item. So what I did here is, I think it is parens on the request if it contains the parenthesized parts of a regex. I'm just going to send it back to see if it actually works. So let's restart the server. Let's split our screen into-- where is my Chrome? There we go. This is too small. So if I go here, we shouldn't see much. But if I go here, yeah, we have About. If I go by Contact, we have Contact. Exactly what we want. PAUL: One question that's come in is, the routing that we have here effectively, it's different to the front end code that we had. SURMA: Totally. PAUL: And today, are we going to cover off using the same routing, or are we completely avoiding that for this? SURMA: No. PAUL: Cool. SURMA: The code that you wrote in the route advanced-- PAUL: Was a disaster. SURMA: No. That's what you said, not me. It's mostly going to remain untouched. We've got to do a little of tricking later maybe. If we get to it, I have an idea that I want to try out. But for now, we're just going to do the delivery part. I mean, if we get this done, it might be interesting to talk about writing JavaScript works in the front end, in the back end, maybe even the service record. Which is the trisomorphic JavaScript, which is a great buzzword that people came up with. But that's-- PAUL: For the future. SURMA: For now, let's start-- PAUL: [INAUDIBLE] that must be server side, client side, and service worker based routing. SURMA: Yes. Which eventually, maybe. PAUL: Terrific. SURMA: So we figured out what our item is, so we can just put this in this great template expression. So I'll just put item here. And what we're going to do next is we now have an array of files. So in case you don't know, read file returns buffer objects. We don't want buffers, we want strings. So what we're going to do is we're going to map over all our files and say to string. And say this is UTF-8 encoded, and now we have an array of strings, and not an array of buffers. PAUL: Oh, easy. SURMA: That is so easy. Now, what we're going to do-- PAUL: Typo. SURMA: Are you going to call me out on any [INAUDIBLE]? PAUL: Yes. SURMA: We have an error strings, so now we can do response, send files, join like this. And because we're good, we're also going to catch our errors. So if any of these fail, because, for example, if any of these files don't exist, the promise.all will not resolve but reject. And now we can handle that the catch part of our promise chain and say, a response should have a status of 500 for now and send the error to string. So we're actually doing error handling, which usually in one-off code doesn't happen. So that is pretty cool. PAUL: So it doesn't in mine, as we may have noticed. SURMA: So let's restart our web server, and let's do curl, because we haven't done curl yet. Actually-- you know what, let's do curl. We're going to use dash I, so we want to see the headers. But we're also going to use dash k, that means ignore certificate errors. Because, as remember, we're still serving over TLS with a self signed certificate, and curl is going to reject unless we give it dash k as an option. PAUL: Please tell me you know that stuff by heart, as well. SURMA: I've done so much curl that I actually know these, too. PAUL: Well, hey, server error. Oh, it's undefined. Why's it undefined? SURMA: Well, that's not nice. PAUL: Items, the param zero. SURMA: Because if it's undefined, we're going to use just an empty string. PAUL: Oh, OK. SURMA: The easy fix, right? Let's restart the server, do another curl. There we go. So we have reassembled the entire file, because you can see the header and the footer. However, if you take a closer look, you will see that we have five ST views. Because our header has all the remote views, and then we basically reiterate the home view with the actual content. Which it I don't even know if your code handles this. PAUL: No. Don't do it. SURMA: I want to see it break. PAUL: It's going to break. SURMA: Let me open the console for more fun in the error department. PAUL: Oh, thanks, pal. It's just broken. SURMA: There's not even an error. PAUL: It's just broken. It just-- yeah. SURMA: Let's look at the code, but it should be--yeah. So as you can see here, I can zoom in a little bit. We have five sc-views, which is not what we want. So let's fix that. And one typical thing, or one easy way to fix it is to turn our partials into a templates that we can use with a template engine. And my template engine of choice in this regard, because I know it pretty well, is handlebars. PAUL: OK, yeah, that's pretty common. SURMA: So what I'm going to do is I'm going to require in Handlebars. Require handlebars. PAUL: So got a question here. Is it normal to end up with routing in three places, or is that a no-no? SURMA: Currently I would say it is pretty normal. I'm assuming that something like for isomorphic-- at least isomorphic you can use in the front end, and your service worker is going to become a pretty common practice. PAUL: So I think there's a distinction here between just having the routing all together. SURMA: Yeah. PAUL: So when you do progressive enhancement, you're going to build routing on the server side like this anyway, right? You're just going to do. SURMA: You're going to usually have APIs ice and content delivery, all these kind of things in your app. PAUL: Right. And then you are probably going to progressively enhance into some routing on the client anyway. And then if you progressively enhance to have a service worker, you're going to have routing in there. You might do a pass through, actually. Just kind of going, well, unless what you're building streams on the fly in the service worker, for example. SURMA: Don't say that to him, that'll be really bad. PAUL: He will come back in the room if I say streams too loudly. That's Jake, by the way. SURMA: You're safe, I think, so far. PAUL: So far. Sound-proof wall. SURMA: OK. Good investment. PAUL: Anyway, it's probably pretty normal. Whether it's actually the same code, the isomorphic, trisomorphic thing. SURMA: So personally I'm not a big believer in trisomorphic. Because even though I'm writing Note right now, that's not the only language you can use on the back end. There's like, Go, Python-- PAUL: DHP, come on. You've got to say it. SURMA: There's Java, there's server pages. And you can share JavaScript code with a PHP back end, unless you're doing really weird things. PAUL: Technically there's still cgi bin. SURMA: That is-- yes, please don't. PAUL: OK. So I interrupted you. SURMA: I just imported, required, Handlebars. And now what I'm basically just going to do is, I'm going to take all my files. And for each file, I'm going to say Handlebars, compile this as a template and execute it with a request as the context. So that means that inside our header content and footer, we have access to everything in the request object. But since we have item, I'm just going to add item as a new object to our request so that we have this inside our context. So I'm turning all the files into strings, compiling them with Handlebars, executing them, and then reassembling the website. What we're going to do now is I would like to use Handlebars if, but the problem is that Handlebars if only checks for truthy or falsey values. It doesn't actually evaluate expressions. What I would like to do is if item is equal to home, then I would like to skip this. But actually in this case, it would be empty, because home is the default. But Handlebars can't do this, so I'm going to write my own helper. Which means if not equal. Which doesn't exist yet, we're going to write it. So let's if not equal. PAUL: So we can have one of these for every single section. SURMA: Exactly. So we're going to see if this is for about. PAUL: If you're just joining us, Surma and I are doing some server-side rendering today. We are taking the advanced router from the previous episodes, and we are basically making it, rather than having a bunch of static files, we're now actually putting in some JavaScript to generate these files on the fly. And we are in the middle of that process. You're currently basically making our templates, and making the HTML dynamic so that it can be built on the fly by the JavaScript that we have. SURMA: Well-observed. PAUL: Thank you very much, I am actually here for the duration. And of course, you can join us. You can ask your questions. There are some brilliant remarks already coming in. Unfortunately Jake is still shouting service worker every other second. SURMA: You can't hear it, buit it's there. PAUL: Well, I hear it. I mean, I read it and I hear it, and it's a big problem. All the same, do fire in your questions and your comments, and we'll carry on on this end. So you go Handlebars, you're making these dynamic. SURMA: So we just used if not equal, even though it doesn't exist. So let's better make it exist. So there's a register helper call, if not exist. And this is where Handlebars turns into black magic, because it just gives you as many parameters as the helper takes and a magic options element at the end. But we're going to do here is we're going to check if A is not equal to B. We are going to options function this. Now this is just something I have to admit I memorized this. Because what this does is the options object contains the function that will generate the string that is in between our mustache braces in the mark up code. And this is just the context that we passed it originally, so that is going to be the request object. Basically what we're doing is, we're only going to render the things in between our if not equals blocks if A does not equal B which is what we want to say with if not equal. So fingers crossed if this actually works or not. I'm going to restart my server, I'm going to expect some text errors. PAUL: There aren't any! Oh, you. SURMA: Big showoff! Oh, yeah. So let's restart this. That's actually a little bit big, isn't it? PAUL: That looks like it's actually correct, because you're going straight to the Contacts section. SURMA: We can click again, and it's got-- look at the code. And as you can see, we only have four sc-views. And the one that is actually live is missing from the remote ones. PAUL: OK. Wow. SURMA: So it achieved our goal of only rendering certain parts depending on what page we are currently on. So that means we basically just achieved our server-side rendering. We are injecting the content that is actually requested before any JavaScript on the client side runs, and yet we are more or less just delivery on the same page over and over, our head and our footer. PAUL: So what would you do in terms of, say, caching this? Because if you build these pages all the time, what would you actually do to say, for example, not have to rebuild these for every individual visitor? SURMA: You know what, let's do that. Let's build good caching headers. So before we sent the file, we just assembled our content. So this content variable holds the actual bytes that we're about to send down to the client. What we could do is you could use these contents to actually calculate a hash value of the contents and use that as an e-tag. So let's do that. Luckily, [INTERPOSING VOICES] Note has crypto. PAUL: Hey, you know in the last episode I asked you what the German was for CSS? SURMA: Yeah. PAUL: Is there an appropriate kind of German term? SURMA: For server-side rendering? PAUL: Yeah. SURMA: Server-side rendering, I guess, could be called [GERMAN SPEECH] which is exactly what we're doing right now. And in case you're German, you know exactly what we just said. PAUL: Again, like always, I've got no chance of either remembering or pronouncing it correctly, but it just sounds so cool. Well, I'm still going to call it server-side rendering. SURMA: If you want to have more German, let us know and I'll make sure it happens. So we have the contents, and what we're going to know is going to calculate the hash. And the hash is going to be crypto create hash, maybe? Actually, let's use Note and say crypto is require crypto, and then crypto create hash. Tag completion, for the win. And we're going to use sha256, because that is decently good. Do some indentation. We're going to append-- it's called update, because you can incrementally add data to a hash, and have it hash it over time if you just have segments. That's why the function is called update, which I find a little bit confusing. And then, in the end, you want to have a digest as a hex value. So that basically gives it a string that encodes the hash value with a hex format. What we can do now, since we have the hash, we can go here and say respond set. Set the call that sets the headers of our response. We can just give it a dictionary. And in this dictionary, we can say, for one, we want to set the e-tag, which is our hash. And because while we're at it we can also set a proper cache control. Public no cache. And this is something I wanted to talk about. Because cache control is such a complex beast. I've been trying to wrap my head around it, and there's so many facets to this entire thing, it can do so much that I just memorized basically two things that I'm ever going to use cache control. It can do, like, private caches, intermediate proxies, you have control over everything. But most of the time, you just want public no cache. And it sounds wrong, but it's not. So something I used before when I didn't know what I was doing was must revalidate. Because that sounds right to me, right? PAUL: So you are saying is that this should go out, it should try and get it from the server again before anything else. SURMA: Exactly. So I want the client to send a request to the server using the cache checkers like, if none match, or if modified since, to see it should always rebalance the server if the cached version is still fresh. So up to date. However, must revalidate doesn't do that. Because what must revalidate actually means is, once the resource expires, it should be revalidated. So what you would actually have to divide is max age 0, meaning it expires immediately after reception, it should always revalidate. But as it turns out, max age 0, and it must revalidate, there's a short version, which is called no cache. So even though it says-- PAUL: Typo. SURMA: So even though it says no cache, caching is actually still happening, but with a validation front route. PAUL: OK. So we got a question from somebody basically asking whether the code will be visible somewhere after the session. SURMA: Of course. As always, we're going to put it onto our gitHub repository. we're going to link it up in the video description I guess it's on our Google chromo or get up and everything's going to be in there as it always has been with all other questions. PAUL: Yeah, it goes in our kind of umbrella. It's github/com/googlechrome/ui element samples. We will link it, you can find it based off previous episodes, it's always within the description for that, and this code will go up there. Bit of a funny name, UI element samples. This isn't really UI work today, but I hope you'll understand. SURMA: It's sort of, but differently, and evolved. PAUL: So your no cache is basically there to do the max age zero must revalidate, squish it down to no cache. It's a kind of a shorthand version. SURMA: Exactly. It's just a shorthand, really. PAUL: Brilliant. SURMA: So let's see if I did this right. I'm going to kill the server, restart it. Still no error, which is eerie. I don't trust it. know Let's use Curl. And actually I'm going to use capital I, which means only show me the headers because I don't care about the content right now. And actually, let's start with static fjazz. Which is a file as we tested before that is delivered by the middleware. So we should have the somewhat weird weak e-tag. PAUL: Which we do. SURMA: Sure enough, we do. And now let's request something that is delivered by our own function, and we should have a really long e-tag, a sha256 hash, which we do. PAUL: And we also get your public no cache there, as well. SURMA: Exactly. So that means that when assembling the header, the content, and the footer, we will recalculate this hash every time and the user will only redownload it if they don't have it cached already. PAUL: Perfect. SURMA: Which is nice. So now we have caching. Ideally, probably, we would write a little more complex code to not recalculate the hash value every time. But these are the kind of things that I say, this is not production code. This is more about-- PAUL: Right, and you'd probably consider a CDN, and other kind of intermediate caches, and so forth to make sure that things only hit your server when they absolutely have to. But for the purposes of today, we're showing-- and this does come up on the chat sometimes. We aren't always going to jump to a final solution that, maybe, a prefabricated one. And the reason is not because we don't like them, often they do a very, very good job. But this is our opportunity to kind of show the underpinnings, if you like. SURMA: The essentials. PAUL: Yeah, the essentials. The engine inside so that it's about the principles more than the code. SURMA: Also, I think we're both kind of of the opinion that you have to know the basics that certain frameworks are built upon to be able to fix them if they don't do what you want for once. Which, if you use favx, you will have run into the problem that something is not doing the thing you would like it to do. PAUL: Maybe you go somewhere and they say, you know what, all we do is write Python. And you think, I don't know, I'm used to writing in JavaScript and Note. What do I do? Well if you know the kinds of things, the kind of headers you should be setting, the kind of ways you might be able-- it's more a case of plugging things together rather than anything else. SURMA: It's what you do versus how you do it. PAUL: There you go. Right. SURMA: Quote me on this. All right. So technically, we just got server-side rendering, which is really, really cool. So if we go here, they should all be working as it is before, and we're actually assembling these pages on the fly. However, something that might be a little-- here, let me-- can I disable cache? Let's disable cache, because I see that we get three or fours, which is not modified. PAUL: Which is good, right? That's what we wanted. SURMA: That's exactly what we wanted. But in this case, I wanted to point out that if we don't have caching enabled, that if the site downloads contacts it actually downloads the entire site. Even though, again, header and footer are pretty much the same. And if you look at-- the only [? count ?] we actually need from Contact is this single line. So we're actually pretty being pretty wasteful with the data that's being downloaded when the user switches to another tab. PAUL: So a little bit more context here, I think, is that in the JavaScript code, we download the full document, don't we? SURMA: Let's look at the header. So yeah. We basically would say the route is this one. Oh no, actually when we go to About, the sc-view requests this website from the server, the entire thing, and puts it into the Dom. Pulls out the part that it needs and switches out the-- PAUL: But it downloads the whole document and then query selects it out, only that little bit. So you're saying what we should be doing is just to send down that little bit. SURMA: Yeah. Since we're going to throw away the rest anyway, might as well do it on the server side. So look at our index.html route, I guess. We could do something really sneaky. What we could do is we could add support for a curry parameter. So right now, if we do something like this, you will get the entire site. Look at the entire site. What would be nice is that if we add something like the partial, that we only get the bits that are actually relevant for our server side of or client side JavaScript. So what I'm going to do is I'm going to check if partial is in the request query dictionary, and now add logic. So as you can see here, we have a lot of files that are being read. But if we have partial, we actually only want to read-- PAUL: Typo. SURMA: We only want to read this file. My copy-pasting is off the charts today. PAUL: Still better than mine! SURMA: So we're going to use let for once, we're going to use let because we're going to change it. If we have partials, we're just going to read one files. If we don't, we want to read all the files. Boom. PAUL: OK. So you ask for partial, we'll only give you the little bit in the middle. If you don't, we will give you the header, the middle, and the bottom. OK. SURMA: So promise all files, which sometimes might be an area with just one item in there, and sometimes with three. PAUL: Somebody is asking, what is the actual benefits of server-side rendering? SURMA: User experience mostly. I think I touched on it earlier at the beginning, I guess. If we didn't do this, and we didn't do rendering out all the pages ahead of time and saving them as individual files, the user would have to wait for the JavaScript to spin up. PAUL: So you would download all the JavaScript, build the page on the client, and then inject that HTML. SURMA: And usually in between, there's also a request to the server to get the actual data that the user wants to see. Or you have to maintain multiple copies of the same index HTML, which is probably more developer experience, but also means it was very error prone. Because the second you do something wrong, everything can break apart. PAUL: Yeah. One of the superpowers of the web, as well, it is really worth pointing out, is its ability to stream. If you look at a large document-- SURMA: You said it! PAUL: If you look at a large document on the web and it's, like, several megabytes large, it can still render after the first few kilobytes have arrived. Because it has, hopefully, potentially for some inline styles, it's got enough to get something up on screen. If you're gated on your JavaScript, you have to wait till-- it's like an entire kind of bulk download is finished before you can get anything on screen. And so having something where the server can immediately respond by going, look, here's some HTML, and ideally some inline styles or whatever. Get that up on screen. And when the JavaScript and everything else is ready, then you can progressively enhance into other things. That's good if JavaScript breaks, which is something that can happen in reality. SURMA: I was just on a vacation in Indonesia, where internet is noticeably slower than what we're used to here. You really feel the difference of a website that do care about delivering the right content on the very first response versus the site that needs JavaScript and everything to just get started. PAUL: Basically, performance and resilience are at least two. SURMA: And since it's performance, we're doing it on Supercharged. PAUL: Carry on, carry on. SURMA: I will. All right, so we have files false, and the rest stays the same. So if it's just one file, we're still going to turn it into a string. We're still going to compile with Handlebars, even though nothing's going to happen there. And then we're going to create a hash inside the headers and send them back. So the pipeline stays exactly the same, we just added one if to handle partials. So let's see with Curl that it's actually doing what I want. So I'm going to reset-- syntax errors! PAUL: You got one. Oh, it's outside street mode. Now, didn't you say to me earlier, I'm pretty sure that ES2015 code is-- SURMA: I think that's the case. Apparently-- PAUL: Apparently you need to put it in use strict. I think in new versions of Note you don't need to put in use strict. SURMA: Maybe I was on Note 5. PAUL: Yeah, Note 5, 6, I think. So yeah-- SURMA: Let's give this a try again. PAUL: That's a good start. SURMA: I can live with that. So let's start, does the old version still work where we get the entire document? Yes, it does. And let's add partial, and we just get a single line. Which is awesome. And also it has a different e-tag, because it's a different document, which is good. So let's actually go into your code. I get to patch up your code. This is so exciting. PAUL: What are we talking about? I write flawless code. SURMA: Is it? Lets look. Is it the router? PAUL: I'm not going to help you know, am I? SURMA: No, it's the view. Because the view takes care of actually loading the data for itself, because, you know, that's actually sensible design. PAUL: Oh, now you recovered it. SURMA: Saved it! All right, so somewhere in here we should have the XML HE requests. This is the on-load event, there we go. So what you do is you just use data, which is, I think, the part of the URL that we've just navigated to. And the only thing we have to do, really, is to append partial. I don't trust this. So I add a partial. That means that now our decline site code should only load the data it needs to refresh the views. Let's go back to the browser. Let's go back to Home, and refresh. And because we have the preload headers, we already loaded the different-- I mean, it can go here. It should still work. So everything looks right, that is good. So it's still working. And let's take a look at what About actually loaded. PAUL: Somebody is asking if, when you get a moment, can you disable JavaScript and just show the benefits of side rendering when this is done? Because we can just switch off JavaScript, right? And then it would just show that the links actually work without-- SURMA: Well, yeah, yeah they will. Let's reload. Let's go back to home, let's reload. Hide the console. I'm going to click on About, reload it, About, partial. And that means within response, we only load in a single line of markup instead of the entire document. Which is, yay, winning for us. So we're going to save a lot of data. So now let's do that, since this seems to be working fine. We disable JavaScript. Home, Refresh. PAUL: OK, click around, About, Contact. SURMA: See, there's no animation because we have no JavaScript. PAUL: It still works, you're still getting to the-- SURMA: This is progressive enhancement done right. Because even with our JavaScript, the site is actually fully functional. PAUL: Winning. SURMA: This is really, really good. And then we just enable JavaScript again, we reload our website, and we get our nice switchy animations. So in the end, we just wrote a backend in about 70 lines. I want to give this one more try. PAUL: OK. SURMA: Actually, I've been on speedy the entire time, and we're still on HTTP1, right? PAUL: Yeah. SURMA: I have no idea what's going on here. I'm going to blame Note 4. PAUL: OK. That seems like a thing you can do. SURMA: If you want to know why this didn't work, follow me on Twitter, @DasSurma, and I will figure this out. Because this is bugging me. PAUL: Yeah, well, it's the only issue you had, and you had it early on and you recovered beautifully, I must say. Are there any other questions on-- SURMA: Yeah, how is the chat doing? PAUL: The chat is doing brilliant. There've been so many great remarks, so many brilliant chats in here. I've been really enjoying it. I see why you do this. SURMA: It is really rewarding. PAUL: It's really good fun. To SURMA: We have very nice people out there in the chat. PAUL: Yeah, so I guess, like you said, we got 70 lines of JavaScript. We're going to push up to the gitHub repo so that you can have a look around, and we'll probably add maybe a few comments here and there. And I'm going to get you to move that regular expression out from there. SURMA: Yeah, I'm going to clean that one up, because it makes your eyes bleed, and nobody knows. PAUL: No, it's not good. It's really not good. SURMA: Even the comment doesn't help. PAUL: All right, OK. Are we done? SURMA: I think we're done. We got sorted rendering in under an hour. PAUL: Perfect OK, well in that case, I guess all that remains is for me to say thank you to everybody who's joined us on the Livestream. Don't forget that you can subscribe. You can follow us on Twitter, I'm @aerotwist. SURMA: And @DasSurma. PAUL: And we will catch you probably in the TLDW. TL-- yeah, too long, didn't watch. It was TLDW. SURMA: It was TLDW. PAUL: Yeah, I got it right this time. Well done me. Normally when they record those videos, it takes me a lot of takes to get even the slightest thing right. It's a bit like my typing, it leaves a lot to be desired. SURMA: It's his life. PAUL: On that exciting note, we'll catch you next time. SURMA: Thanks for watching.
Info
Channel: Google Chrome Developers
Views: 31,821
Rating: undefined out of 5
Keywords: Chrome, Developers, Google, Web, Supercharged, Server, Side, Rendering, Live Coding, Live Code, Aerotwist, Paul Lewis, Surma
Id: 8LM4p7l9YMY
Channel Id: undefined
Length: 55min 56sec (3356 seconds)
Published: Thu Sep 15 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.