In this series of blog posts, we’re looking at how to set up a simple web app in node.
In the previous installment we got the basic set up running. In this post we’re going to put the plumbing in for serving html, both static and dynamic pages.
Serving static files
We could serve static files using express to match on a given path like this app.get('/filename', ...) and returning the file in the response. However, this gets quite tedious. A much easier approach is to set up some middleware to handle static files.
Hold on, what’s middleware?
When express processes an incoming HTTP request, you can register your own code to run as part of this pipeline. Middleware is the opportunity to hook into all incoming requests, or just requests to a specific path. For example, you could register some middleware to ensure that requests are authenticated, or to decode specific content types.
We’ll register some middleware which will intercept requests matching the name of a static file and serve it for us.
To do this, add this line to server.js:
var path = require('path');
app.use(express.static(path.join(__dirname, 'public')));Let’s unpack this line of code:
require('path')will load a module for working with directory names. It’s a module that comes with node, so you don’t need to use npm to install it.__dirnameis a variable in node, giving us the name of the directory which contains the script file.path.joinwill append file system paths together. So here we’re appending ‘public’ to the current directory.express.staticis the middleware which serves static files.app.useregisters middleware for every request.
So this line instructs the express app to serve static files from the ‘public’ directory.
Express is sensitive to the order middleware is registered, you need to add it above any of your routes, but after the app is created.
Your server.js should now look like this:
// load the path package
var path = require('path');
// load the express package
var express = require('express');
// create an express application
var app = express();
// register middleware to serve static pages
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', function(req, res){
res.send('hello world');
});
// start listening on port 8080
app.listen(8080);Now, lets create a public folder:
> mkdir publicYou can add a file in there, perhaps a favicon (favicon.ico).
You’ll have to restart your node process, but you should see your file is now being served.
This allows you to serve static assets from your node app, without your application code needing to be concerned about what the files are. Any request that comes in and matches a filename will be automatically served for you.
Server-side templating
We don’t want to just serve static file with node, we want to use some logic to create dynamic content.
My preference is to use mustache templates for converting data into html. So let’s plug mustache in.
Hogan.js is a JavaScript implementation of Mustache, and hogan-express allows you to easily hook it up to express.
Install the module using npm:
> npm install hogan-express --saveNow let’s register the middleware to handle the views:
app.engine('html', require('hogan-express'));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'html');
app.set('layout', 'layout');These lines can be placed immediately above the app.use we wrote earlier for the static files.
Let’s unpack this code line by line:
app.engineregisters a templating engine. Here we pass in the ‘hogan-express’ module, and register it as the templating engine for html.app.setsets an application setting. First we set theviewssetting, which is the directory where the views are stored. We use thepathmodule again to refer to a sub-directory calledviews.- We set the default view engine to be html (which refers to the one we registered on the first line).
- Finally the
layoutvariable is the name of the view which is used as the template.
Now let’s create a directory for our views;
> mkdir viewsWe can add a layout.html file to this directory, which will contain our template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> { { title } } </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"></style>
</head>
<body>
{ { { yield } } }
</body>
</html>I have had to put spaces between my curly braces, as jekyll got upset when it saw multiple curly braces next to each other. Please remove these spaces in your views
Note that we’re referring to the bootstrap stylesheet hosted on a CDN.
Now let’s create a simple view to show the current time.
<div class="container">
The time is : { { time } }
</div>Call this time.html, and add it to the views directory.
Now we need to go back to our server.js file and wire it up.
Replace the app.get('/' ...) code with this:
app.get('/', function(req, res){
res.locals.time = new Date();
res.locals.title = 'the current time';
res.render('time');
});Let’s unpack the code:
- We create a new data object (which is initialised with the current time), and sets a
timeproperty on ares.localsvariable.res.localsallows you to pass data into the view. - We also use
res.localsto set the title of the page, which is in thelayout.htmltemplate. - Finally we tell express to render the response with the
timetemplate.
Our server.js file now looks like this:
// load the path package
var path = require('path');
// load the express package
var express = require('express');
// create an express application
var app = express();
// set up hogan for rendering views
app.engine('html', require('hogan-express'));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'html');
app.set('layout', 'layout');
// register middleware to serve static pages
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', function(req, res){
res.locals.time = new Date();
res.locals.title = 'the current time';
res.render('time');
});
// start listening on port 8080
app.listen(8080);That’s it!
We could of course listen to more paths, and create more views.
Next we’ll look at reading and writing to a database - the node way!