My blog, as if written in Node.js - part 1.

4

An introduction to web development using Node.js and express.js.

on 22/11/10

Node.js is a server side JavaScript platform built on top of Google's V8 JavaScript engine. It is centered around a single-threaded, event based I/O, making it suitable for building scalable network programs. As such, building a blog does not really take advantage of Node's true strengths, but it does provide a familiar topic as the basis for our learning.

When getting started with Node, the choice of which Node modules to use is a little overwhelming. I had a quick look through a lot of then and tried to map out a stack for my application - I settled with: express.js web framework (which is built on Connect), EJS Embedded JavaScript templates and a Node Mysql module by Felix G. whom I know produces great quality work from all of his CakePHP contributions.

Installing Node.js

I recommend downloading the latest stable release. From there, explode it into a folder, and then:


./configure
make
make install

You should also install NPM (Node Package Manager). This should be as simple as:


curl http://npmjs.org/install.sh | sh

If you run into Permission Errors, then check out your options for resolving those in isaac's readme.

Installing the express web framework

I installed express using NPM via the following command:


npm install express

Project structure overview.

Before we get stuck into things, I've included a screenshot of my current project layout here, because it was one of the first things I came across and wasn't sure about.

Good project structure, and following conventions, are both incredibly important in producing a project similar to the way other developers would expect it.

I have free-styled a bit here, a little bit CakePHP inspired, a little bit gut-instinct. In reality, I will probably gain more exposure/experience and re-evaluate my project structure over time, ultimately incorporating it into my own project framework/scaffolding.

Don't worry about stubbing out the files based on this image - we will get there in good time.

The web server, server.js:

The very first thing the Node.js website teaches you, is how to write a basic web server using Node!


var http = require('http');
http.createServer(function (req, res) {
	res.writeHead(200, {'Content-Type': 'text/plain'});
	res.end('Hello World');
}).listen(8124, "127.0.0.1");
console.log('Server running at http://127.0.0.1:8124/');

I have chosen to use the Express framework, so my server is set up in a slightly different way, but the concepts are the same. The following is my web server setup:


// Import express, made available via NPM.
var express = require('express');
var app = express.createServer();

var PORT = 8080;

// Set the default view engine to EJS.
app.set('view engine', 'ejs');

// Configure the app.
app.configure(function() {
    app.use(express.methodOverride());
    app.use(express.bodyDecoder());
    app.use(app.router);
    app.use(express.staticProvider(__dirname + '/public'));
});

// [ Some code removed ]

app.listen(PORT);
console.log('Node.js web server listening on port: ' + PORT);

At this point, the code runs but will return an error.
Go on, test it out - node server.js and view the website: http://localhost:8080/
You should experience a: "Cannot GET /" error.

Let's look at a few concepts in the above snippet, before adding some code to fix the error.

  • The convention for importing modules (or libs) is: var module = require('module');
  • We can use __dirname to get the directory name of the script being executed.
  • We can log (to terminal by default) using console.log(msg).

Adding developer friendly error messages:

Add the following snippet of code just before the: app.listen(PORT); line of code.


// Development.
app.configure('development', function() {
	app.use(express.errorHandler({dumpExceptions: true, showStack: true}));
});

// Production.
app.configure('production', function() {
	app.use(express.errorHandler());
});

With these in place, we can now run in development/production mode using:


NODE_ENV=production node server.js

Adding a basic route:

We are now going to add a basic route to our website/app.
Add the following snippet of code just before the: app.listen(PORT); line of code.


// Route :: /pages/hello-world
app.get('/pages/hello-world', function(req, res) {
	res.render('pages/hello-world', {
	    locals: {
			title: 'Hello World'
		}
	});
});

You will get the following error:
500 Error: ENOENT, No such file or directory '.../tonymilne/views/pages/hello-world.ejs'
Let's digest that - we told Express to render a template: 'pages/hello-world'.

Express has a views directory in which it looks for view templates, defaulting to: CWD/views.
We can modify this location using app.set('views', ...);

We told Express that we want our view engine to default to EJS for templates without extensions, when we wrote: app.set('view engine', 'ejs');
This allows us to leave off the extension and it will look for .ejs files automatically.

So, we need to add an empty .ejs file into our '/views/pages' directory called 'hello-world.ejs'.

We now get a similar error, this time because we are missing our default layout. We need to add another empty .ejs file into our '/view' directory called 'layout.ejs'.

A quick page refresh and we now get a blank page. I wonder why? Oh, that's right - all of our views are empty files!

Let's add some layout view code:


<html>
	<head>
		<title><%- title %></title>
	</head>

	<body>
		<div id="page">
			<%- body %>
		</div><!-- end page -->
	</body>
</html>

The main thing to note here is that we are passing JavaScript variables to the template and letting EJS render them for us using the <%- %> tags. It effectively means evaluate and print what is returned within the tags, similar to a PHP echo statement.

Now let's add the hello-world view code:


<h1>Hello World</h1>

A quick page refresh and we are greeted with the familiar: "Hello World".

To be continued...

In future post(s) within this series, I will be covering:

  • using one route callback for multiple routes
  • mysql connectivity from within Node.js
  • and some more complex EJS techniques (including helpers & view partials with collections).

Matt Dobson

  -  http://www.evokeone.com/

on 7/2/11

I have been looking for something like this for a while. Really great introductory post. Looking forward to seeing future additions to this guide!

Peter

on 9/2/11

Hi Tony, very interesting post. Would be good to discuss it further if you have some time!

Rob Levin

  -  http://developtodesign.com

on 19/12/11

Nice post. I was trying to figure out how I could get additional "partials" in my views and your <%- title %> example was all I needed. So it seems that you can render an entire page or pass in vars to locals and they can be "seen" by the .ejs accordingly.

Mark Brown

  -  http://yellowshoe.com.au/

on 23/8/12

Looks awesome. I've tinkered with Node but want to get more into it and learn how you can make a good Rails-like structure for it. Cheers!

You should leave a comment:

Some tags are allowed: (a, b, blockquote, code, em, i, u, pre, strong).

who am I?

I live in Melbourne. I work at Inlight Media. I'm passionate about web and software development. I like jQuery, CakePHP, Flex. I can code. I can't draw. I play basketball with the Spiderpigs and the Generals. I love snowboarding in the winter and wakeboarding in the summer. I play computer games too often.