Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript Build a Simple Dynamic Site with Node.js HTTP Methods and Headers Perfection Suggestions

Oliver Duncan
Oliver Duncan
16,642 Points

Loaded static CSS, now just wondering how it works.

With the help of some of my fellow Treehouse students, I was able to load a css file through the server by adding conditionals to createServer(). Here's the code:

//Function that reads css
function css(location, response) {
  //Read css file
  var cssFile = fs.readFileSync('./css/main.css', {encoding: 'utf-8'});
  response.writeHead(200, {'Content-Type': 'text/css'});
  response.write(cssFile);
  response.end();
}

My question is this: if every router function (home, user, and css) has a response.end(), how are the html and css loading concurrently? Additionally, since we're using readFileSync(), I was under the impression that these functions would block others until complete. How are CSS and HTML being read and interpreted at the same time? Thanks in advance.

Oliver Duncan
Oliver Duncan
16,642 Points

Also working on another simple node website from scratch, and used this code to read css and .js files:

http.createServer(function(request, response) {
  if (request.url.indexOf('.html') !== -1) {
    response.writeHead(200, {'Content-Type': 'text/html'});  
    response.write(fs.readFileSync('./index.html'));
    response.end();
  } else if (request.url.indexOf('.js') !== -1) {
    response.writeHead(200, {'Content-Type': 'application/javascript'});
    response.write(fs.readFileSync('.' + request.url));
    console.log(request.url);
    response.end();
  } else if (request.url.indexOf('.css') !== -1) {
    response.writeHead(200, {'Content-Type': 'text/css'});
    response.write(fs.readFileSync('.' + request.url));
    console.log(request.url);
    response.end();
  }
}).listen(3000);

Works like a charm, but there's something confusing me. I also added a css normalizer and jQuery, which seem to loading to the webpage. However, they're not being logged to the console and I would think that adding a '.' before 'https://code.jquery.com/jquery-3.0.0.min.js' would break the function. Anyone know an explanation?

I think this might work for my image problem... I need something that will tell it the content type, but let me send any image name.

Brendan Moran
Brendan Moran
14,052 Points

in the context of what Andrew taught us in the lesson (the code we have built following his lead), where did you declare this function and where did you call it? I am having trouble figuring this out.

2 Answers

Oliver Duncan
Oliver Duncan
16,642 Points

Brendan: Wherever you declare the function that loads static files, you'll need to have a conditional statement in the body of the create server function. Check out my second example above for my implementation.

My first example was declared in the Router module, and was called in the body of createServer if the request url contained ".css".

Think of it this way: your html contains a link tag to your css file. When your browser sees the link, it sends a request to your server for that file (using the url property of the request object, i.e. request.url). To correctly load the page, your server needs to be able to know what kind of file is being requested, so it can load the correct content-type. That's why we set up a conditional statement; the server reads the file extension and loads the file with the right content-type.

Brendan Moran
Brendan Moran
14,052 Points

Thanks! That helps. I got this working a bit after I left my original comment. It took some careful console logging to really visualize what was going on, but now I've got it! Thanks for your help.

I've realized something else that's interesting: in your CSS function, you don't need to set the encoding to utf8, the buffer will work fine. I realized that we only set the encoding to utf8 with the HTML templates because we needed to use a string method to search them for the {{variableNames}}.

Also, I am finding that even if I eliminate the writeHead, everything still works. I looked this up and apparently node will figure out what the head needs to be on its own. So now that has me asking: why did Andrew manually set the head using writeHead in so many instances? From what I read, the only time it is really necessary is when we are wanting to perform some kind of unexpected behavior, like our 303 redirect with the username search. Do you have any insight on that?

Oliver Duncan
Oliver Duncan
16,642 Points

I knew about leaving out encoding, but I've never left out writeHead. I'll have to try it. My guess is that either Node didn't write the response header for you when the video was made, and does now, or Andrew just wanted us to see how common requests and responses were made and handled. Either way, glad you found a solution.

I used the {{variable}} syntax in my header.html file then sent the "css/styles.css" as a replacement. It works great for the CSS file, and would probably be fine for loading some custom javascript, but I just discovered I need to be able to do something like this to add images... there has to be a better way than coding each one by hand.

<head>
  <meta charset="utf-8">
  <title>Online Marketplace</title>
  <link href="https://fonts.googleapis.com/css?family=Cantata+One" rel="stylesheet">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
  <style>{{stylesheet}}</style>
  <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
</head>

The code that calls this in my routes.js file:

function index(request, response) {
  if(request.url === "/") {
    response.writeHeader(200, {html});
    views.view("header", {stylesheet:"css/styles.css"}, response);
    views.view("index", {}, response);
    views.view("footer", {}, response);
    response.end();
  }
}
Oliver Duncan
Oliver Duncan
16,642 Points

Yeah. Adding

if (request.url.indexOf(".png") !== -1) {
  //write image to response
};

might do the trick. I haven't loaded an image yet, but I'm gonna give it a try when I get home.