Check out a free preview of the full Real-Time Web with Node.js course:
The "Serving Static Files" Lesson is part of the full, Real-Time Web with Node.js course featured in this preview video. Here's what you'd learn in this lesson:

Up to this point, Node has been pushing content to the browser using the write-stream API. Kyle now modifies the node application to serve static HTML files. Kyle also field a few questions about keeping track of useful node modules.

Get Unlimited Access Now

Transcript from the "Serving Static Files" Lesson

[00:00:00]
>> [MUSIC]

[00:00:04]
>> Kyle: All right, let's take our file save as and let's go to 6.server.js. And now I'm gonna be able to reveal to you why it was that I started naming these files with different numbers like this. Because the next question that we might ask, was clear that if we wanted to print out a hello world with a random number to it.

[00:00:25] Then we can just call res.writeHead or res.end. But what about when we're throwing out entire HTML pages of content from a templating engine or something. We don't be calling .writes over and over again for all of our page content. In fact, what about all of our static files that we might wanna serve up like our JavaScript files and our CSS files.

[00:00:45] We don't wanna manually do a fileRead stream and read those in and pipe those out. That's way too much work. So, some people feel like nodes shouldn't serve up static files and so they will write a node instance that handles kind of your server API. But they'll host all of the static files for an app on a different domain on a CDN or on some other kind of web server.

[00:01:07] And that's a perfectly valid way of going about it. But I just wanted to also show you if you wanted to serve up static files from inside of node. A simple way to do that without a big complicated framework. There's a simple little tool that we're going to install.

[00:01:21] So the first thing we'll do is go to our command line. Stop that process from running. Go to our command line and do npm install node-static. Again, if you've already got it, you won't need to run it. But if you don't have that installed yet, do npm install node-static.

[00:01:38] Then it'll load a whole bunch of sub-dependencies and things like that. But it'll load up a little module that we're gonna be able to use to spin up a static file server for our static files. [COUGH] Then we'll come back to our system. I want you to create a brand new empty file and call it 6.html..

[00:02:00] So we're gonna have a 6.server.js and we're gonna have a 6.html. And inside of that, just make yourself a real simple plain HTML page. Make sure it has some sort of identifying information in it that lets you know which version file you're looking at, 6.html for instance.
>> Kyle: Okay, I've created myself an HTML fil, now I would like to be able to serve up that HTML file when I make a request to the website.

[00:02:56] So we're gonna get rid of now this whole slash business with the randomly generating hello world stuff and you don't technically have to remove it. But let's just get rid of it cuz we're not gonna use that in any more of our things. So we're gonna set ourselves up with another path here.

[00:03:13] And so what we wanna ask is if we request a file of a particular type of a particular your URL pattern. We wanna handle that as a static file request, otherwise we don't wanna handle it, okay? Now, rather than have you try to retype this regular expression which may be more difficult.

[00:03:31] I would recommend you go ahead and open up the solutions folder version of 6.server to see you can do a copy and paste. Cuz there's some regular expression stuff that I'm doing here that you may not wanna accidentally get not quite right. So just copy and paste in that if clause from the other solutions file and I'll explain to you what it's doing.

[00:03:52] On line 3, we've got a regular expression there that is saying, if my request.url starts with the slash and has one or more numeric digits. That's what the \d is. And then we're doing an assertion that says that it ends either with the end of the string. Or with one of the URL separator characters like the slash, the question mark or the hash symbol.

[00:04:19] If any of those things come after it, then that's a URL that we wanna recognize. In other words, if the URL says /6, then we wanna recognize it. But if it says /abc or /foo, we don't wanna recognize it. Does everybody follow? So it's a slightly more complicated if statement for doing some pattern matching on our request URL.

[00:04:43] Now, leave that if statement for alone for a moment. Let's come down here to the bottom, we need to create a static file server. So we need to include node static, so I'm gonna say var node_static = require("node-static");. So I use the underscore there because hyphens aren't valid JavaScript characters.

[00:05:05] But I've got node_static = require("node-static");. And then I need to create a static files server instance, I'm gonna say var static_files is equal to node_static. I'm sorry, I need to put a new in front of it, the way it works. I forget what their syntax is. It's always hard to remember everybody's different syntax.

[00:05:34] Let me check them out quick.
>> Kyle: New node_static.server, there we go. So capital S server. Now, it asks for a directory name for the first parameter that we pass. So node has this special variable called __dirname, __dirname. That will always resolve to whatever the current directory is that the current node program is running in.

[00:06:00] So it's a magical property that always reserves to that and that's the directory that we wanna serve up our static files from. So that'll work just fine, we'll just use that static file server. Now we come up here and I'm gonna do a little bit of a URL rewriting magic to basically take anything that was slash number.

[00:06:21] And I'm gonna ignore everything else that was in the URL and I'm gonna return the URL into /number.html. So in other words, if the URL says /6, I wanna treat it as if the URL said /6.html. Now again, there's lots of different middleware frameworks out there, many of them allow you to do fancy pattern matching and even URL rewriting stuff.

[00:06:46] I'm just showing you what plain old simple JavaScript functions with regular expressions and string manipulation. We can do those things ourselves, we don't need fancy frameworks for it. When I'm gonna change it so that if I asked for /6 that I really meant /6.html. And then I'm just simply gonna tell the static files module to handle the rest of my request response, cuz I don't wanna do that work.

[00:07:11] I don't wanna stream in the contents of the file. I don't wanna try to figure out what content type it should be or what the content length is, any of those details. That's more work than I wanna deal with. So the static file server will sniff the MIME type from the file extension.

[00:07:27] It'll check the file type of what it sees, it will try to figure it out. It makes a really good guess about serving up your file properly. Everybody with me so far? All right, now that we have 6.server.js. If we come back over here to our command line and we say node 6.server.js, our server will start running.

[00:07:54] Now if we come over here and we do a refresh without anything on our URL. We expect to get a 403, right, because we no longer have that slash route handling things. But if we now add /6 to our URL, magically we get our 6.html file served up to us.

[00:08:14] And you'll notice if you look down here in your developer tools, not only did we get it but we got it with the correct MIME type and the size contents. And even gzip before us, so everything went exactly the way we would have hoped.
>> Speaker 2: Where did the gzip come from?

[00:08:33] Was that from app static?
>> Kyle: Yeah, the static file server, it's actually capable of doing that and there's more capability there. You can actually pre gzip files and have it serve those up. So there's lots of capability there, we won't go further into that. But that's one of the benefits of using a utility like that, it handles all those sorts of details for us.

[00:08:58]
>> Kyle: [COUGH]
>> Speaker 3: How do you keep track of new utilities and have which ones might wanna use. I mean it isn't just filtering or [INAUDIBLE] a good source [INAUDIBLE] you might point our what kind of [INAUDIBLE]?
>> Kyle: That's a really good question. There's lots of different metrics by which you might judge things.

[00:09:17] So, many people say I just look at the most starred repos on GitHub and I look at the most depended upon repositories on npm. And I know that those are the ones that I wanna go for. So, that's one metric that says the more popular something is, the more likely it is to be of high quality.

[00:09:37] I think another metric that we should pay attention to as I mentioned earlier is, how many dependencies does it have. Because if I look at module A and module B in module A has 1,000 stars and module B only has 10 stars. But module B is way less dependencies.

[00:09:52] That's another metric to consider because even though it has less stars, that might be the better module. At least it might be a module that's gonna take up less of my bandwidth or my files space or something. So, I think there are [COUGH] other metrics to concern yourself besides just is it popular.

[00:10:10] But that's the most common one that people do. I subscribe to a whole bunch of different Twitter feeds, I subscribe to the JavaScript weekly thing and I'm watching in things. But basically what it boils down to is when I come across a task like serving up a static files.

[00:10:25] And I realize that it's anything more than a few lines of writing node myself. I asked myself has somebody made a good module for this? So I do a Google search and I do a GitHub search and I say has anybody made an NPM module for static files serving?

[00:10:41] And I find two or three of them. And I go and look through the GitHub issues and I see whether or not they're paying attention, whether it's an actively maintained project. And I look and see if anybody's been talking about it on Twitter or how many stars it has.

[00:10:53] I look at a bunch of different metrics and I decide which one it's gonna do. But before I even use it, I'll go and open up their code and look at what they did. Because if they're doing something and I can see very clearly that it's something that I could do with a few lines of code.

[00:11:08] Why use the module? There's no reason to add an extra dependency for no reason. So I'll go and look at somebody's code and if it is useful, I'll use the module, if not, I'll do it myself. But that's just my own process, there's no real like good, hard bullet proof way of doing it.

[00:11:30]
>> Kyle: Okay, so [COUGH] 6.server.js is serving up an HTML file for us.