Configuration module

Since we are leaving our server.js file very lean, there is still a fair amount of logic that is required in configuring our server. For this, we will defer to a custom module that we'll create called configure. To get started, create a file named configure.js in the server folder. Let's first install the dependencies that we are going to be using inside our configure module by performing another npm install:

$ npm install express3-handlebars --save

Here we just installed Handlebars, a popular template-rendering engine for HTML pages. Now that the module is installed and ready to be used, let's start writing the configure.js file. First, like any of our modules, we will declare our dependencies:

var connect = require('connect'),
    path = require('path'),
    //routes = require('./routes'),
    exphbs = require('express3-handlebars'),

module.exports = function(app) {
  // configuration code...

  return app;
};

In the preceding code, we declared variables for each of the modules that we will be using in our custom configure module. Then, we defined the actual module that will be exported by this code file, more specifically a function that accepts our app object as a parameter as well as returns that same object (after we make some configuration modifications to it).

Note

You should see that we require Connect, which is actually installed by default with Express.js as its one of its core dependencies. Connect is a popular third-party middleware framework that we will learn more about later in this chapter.

Handlebars view engine

By default, Express can and will happily render static HTML documents and serve them back to the client. However, unless you're building a purely static content-driven site, which is doubtful, you're more than likely going to want to render your HTML dynamically. That is, you want to generate portions of the HTML on the fly as pages are requested, perhaps using loops, conditional statements, data-driven content, and so on. In order to render dynamic HTML pages, you need to use a rendering engine.

This is where Handlebars comes in. The rendering engine is given its name because of the syntax it uses to display data, namely double pairs of braces, {{ and }}. Using Handlebars, you can have sections of your HTML pages that are determined at runtime based on data passed to it. For example:

<div>
    <p>Hello there {{ name }}!  Todays date is {{ timestamp }}</p>
</div>

The actual HTML that would wind up in a visitor's browser would be:

<div>
    <p>Hello there Jason!  Todays date is Sun Apr 13</p>
</div>

The first thing we want to take care of in our configure module is to register Handlebars as the default view rendering engine. In the configure.js file, above the return(app); line, you should insert the following code:

app.engine('handlebars', exphbs.create({
    defaultLayout: 'main',
    layoutsDir: app.get('views') + '/layouts',
    partialsDir: [app.get('views') + '/partials']
}).engine);
app.set('view engine', 'handlebars'),

First, using the Express app object that was passed into the configure function, we define our rendering engine of choice by calling the engine function of app. The first parameter to the engine function is the file extension that the rendering engine should look for, namely .handlebars.

The second parameter builds the engine by calling the exphbs module's create function. This create function takes an options object as a parameter, and this options object defines a number of constants for our server. Most importantly, we will define which layout is our default layout and also where our layouts will be stored. If you recall, in server.js, we used app.set to set a 'views' property of our app that pointed to the current working directory + '/views'. This setting is used when we configure the options for our rendering engine as well. You'll notice that the partialsDir property uses an array (with a single item) versus a single string value for layoutsDir. Both of these methods are interchangeable, and I just wanted to demonstrate that you could have more than one partials directory, and it could just be an array of string values.

With that set, our server now knows that any time we try to render an HTML page that has a file extension of .handlebars, it will use the Handlebars engine to perform the rendering. This means that we need to be sure to use Handlebars-specific syntax in our dynamic HTML pages.

We will be learning more about Handlebars and how to write dynamic HTML pages in the next chapter.

Note

Using .handlebars as a file extension was purely a personal choice. Some people prefer .hbs, and if you want, you can use anything you like. Just make sure that the first parameter to the app.engine() function and the second parameter in the app.set('view engine') function are identical.

Other template engines

There are a number of different template engines available for you to use. One of the more popular engines (and the default engine supported by Express) is called Jade. Personally, I prefer using Handlebars because you use regular HTML, and Handlebars is also a client-side template engine for use in single-page applications with something like Backbone.js.

To learn more about the many template engines available for use with Node, check out this list on the official Joyent GitHub wiki at https://github.com/joyent/node/wiki/modules#templating.

Using and understanding middleware

One of the most powerful features available with Express is the concept of Middleware. The idea behind middleware is that it acts like a stack of filters that every request to your server passes through. Since every request passes through each filter, each filter can perform a specific task against the request before it passes through to the next filter. Typically, these filters are used for tasks such as cookie parsing, form field handling, session handling, authentication, and error handling and logging. The list goes on and on and you can use hundreds of third-party modules as well as simply writing your own.

The order that the middleware is called is very important. Again, using the concept of filters, as a request passes through each filter, you want to be sure that they are performing their responsibilities in the correct order. A great example of this is implementing a cookie parser before a session handler—since sessions typically rely on cookies to maintain state with a user between requests.

Another great example of how the order of middleware is important is with error handling. If any of your middleware encounter an error, they will simply pass that error along to the next middleware in the stack. If the last middleware, regardless of what it is, doesn't gracefully handle that error, it will basically show up in your application as a stack trace (and that's bad). Having an error handler configured as one of the last middleware is like saying "if all else fails, and at any point in the previous middleware a failure occurred, deal with it gracefully."

Introducing Connect

Fortunately, there is a great middleware framework that handles most of the common requirements addressed during the middleware phase. These requests include logging, parsing of HTML form fields and JSON data, cookie and session handling, and more.

Note

Here is a current list of available middleware in the Connect framework:

  • logger
  • csrf
  • compress
  • basicAuth
  • bodyParser
  • json
  • urlencoded
  • multipart
  • timeout
  • cookieParser
  • session
  • cookieSession
  • methodOverride
  • responseTime
  • staticCache
  • static
  • directory
  • vhost
  • favicon
  • limit
  • query
  • errorHandler

Express versions earlier than 4.0 include and depend on these middleware by default. However, starting with Version 4.0.0, support has been completely dropped and certain existing implementations have been removed and moved to their own modules to keep Express as lean as possible. We can safely use and assume that Connect is available when using versions of Express below 4.0. However, if you used 4.0 or higher, you would need to include middleware solutions for each component you are using.

Let's wire up each of the middleware that we are going to need and ensure that they are in the correct order. Note that we are executing our Express app's .use() function, which is how we indicate each middleware that we want to use. Continuing with editing the configure.js file, insert the following code immediately before the return app; line (after the section you just added for the Handlebars engine):

app.use(connect.logger('dev'));
app.use(connect.bodyParser({
  uploadDir:path.join(__dirname, '../public/upload/temp')
}));
app.use(connect.json());
app.use(connect.urlencoded());
app.use(connect.methodOverride());
app.use(connect.cookieParser('some-secret-value-here'));
app.use(app.router);
app.use('/public/', connect.static(path.join(__dirname, '../public')));

if ('development' === app.get('env')) {
    app.use(connect.errorHandler());
}

Let's take a look at each of the Connect middleware we are using in the preceding code:

  • logger('dev'): The logger middleware simply performs a console.log() output of any request that is received by the server. This is very helpful for debugging your node server.
  • bodyParser: This helps facilitate the packing of any form fields that are submitted via an HTML form submission from a browser. Form fields that are submitted via a POST request will be made available via the req.body property.
  • json: Similar to bodyParser except specifically for dealing with posted JSON data via the req.body property.
  • urlencoded: Similar to bodyParser except specifically fields submitted via a GET request will be made available via the req.query property.
  • methodOverride: For older browsers that don't properly support REST HTTP verbs such as UPDATE and PUT, the methodOverride middleware allows this to be faked using a special hidden input field.
  • cookieParser: This allows cookies to be sent/received.
  • errorHandler: This handles any errors that occur throughout the entire middleware process. Typically, you would write your own custom errorHandler that might render a default 404 HTML page, or log the error to a data store, and so on.

The app.use(app.router) line is a special component of Express that says you are actually using a router with your server, and you can respond to requests such as GET, POST, PUT, and UPDATE. Since you are using the Express router as one of the last middleware, we will also define the actual routes in the next section.

Finally, the connect.static() middleware is used to render static content files to the browser from a predefined static resource directory. This is important so that the server can serve up static files such as .js, .css, images, regular .html, as well as any other files you might need to serve up. The static middleware will serve up any static files from the public directory like the following code:

http://localhost:3300/public/js/somescript.js

http://localhost:3300/public/img/main_logo.jpg

It's important that your static middleware is defined after the app.router() so that static assets aren't inadvertently taking priority over a matching route that you may have defined.

Activating the configure module

Now that your configure.js file is complete, you're ready to call it from your main server.js file. If you recall, we included two lines of code that were commented out for our configure module. Its time to uncomment those two lines so that when you run your server, your configure module will do its part. The two lines should now look like:

config = require('./server/configure'),

app = config(app);

Boot up your server again by executing node server.js and everything should still be running smoothly. (Although, the app still doesn't actually do anything yet.) If you point your browser to http://localhost:3300, you'll still get the same error. However, this time, you will see GET / with a 404 log to your terminal thanks to the Connect logger middleware.

Note

When you run your app, you might receive warnings similar to connect.multipart() will be removed in Connect 3.0. This is because Express comes bundled with an older version of Connect and depends fairly heavily on it. With Express Version 4, this dependency has been removed and the Connect framework middleware has been broken down into smaller, separate pieces. More on this is covered in the section later in this chapter, which is related to migrating to Express Version 4.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.158.230