We have a working, blank Express application; let's look at what was generated for us. We're doing this to familiarize ourselves with Express before diving in to start coding our Fibonacci application.
Because we used the --view=hbs option, this application is set up to use the Handlebars.js template engine. Handlebars was built on top of Mustache, and was originally designed for use in the browser; for more information see its homepage at http://handlebarsjs.com/. The version shown here has been packaged for use with Express, and is documented at https://github.com/pillarjs/hbs.
Generally speaking, a template engine makes it possible to insert data into generated web pages. The ExpressJS Wiki has a list of template engines for Express https://github.com/expressjs/express/wiki#template-engines.
The views directory contains two files, error.hbs and index.hbs. The hbs extension is used for Handlebars files. Another file, layout.hbs, is the default page layout. Handlebars has several ways to configure layout templates and even partials (snippets of code which can be included anywhere).
The routes directory contains the initial routing setup, that is, the code to handle specific URLs. We'll modify these later.
The public directory will contain assets that the application doesn't generate, but are simply sent to the browser. What's initially installed is a CSS file, public/stylesheets/style.css.
The package.json file contains our dependencies and other metadata.
The bin directory contains the www script that we saw earlier. That's a Node.js script, which initializes the HTTPServer objects, starts it listening on a TCP port, and calls the last file we'll discuss, app.js. These scripts initialize Express, hook up the routing modules, and do other things.
There's a lot going on in the www and app.js scripts, so let's start with the application initialization. Let's first take a look at a couple of lines in app.js:
var express = require('express');
...
var app = express();
...
module.exports = app;
This means that app.js is a module that exports the object returned by the express module. It doesn't start the HTTP server object, however.
Now, let's turn to the www script. The first thing to see is that it starts with this line:
#!/usr/bin/env node
This is a Unix/Linux technique to make a command script. It says to run the following as a script using the node command. In other words, we have Node.js code and we're instructing the operating system to execute that code using the Node.js runtime:
$ ls -l bin/www
-rwx------ 1 david staff 1595 Feb 5 1970 bin/www
We can also see that the script was made executable by express-generator.
It calls the app.js module as follows:
var app = require('../app');
...
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
...
var server = http.createServer(app);
...
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
We see where port 3000 comes from; it's a parameter to the normalizePort function. We also see that setting the PORT environment variable will override the default port 3000. And finally, we see that the HTTP Server object is created here, and is told to use the application instance created in app.js. Try running the following command:
$ PORT=4242 DEBUG=fibonacci:* npm start
The application now tells you that it's listening on port 4242, where you can ponder the meaning of life.
The app object is next passed to http.createServer(). A look in the Node.js documentation tells us this function takes a requestListener, which is simply a function that takes the request and response objects we've seen previously. Therefore, the app object is such a function.
Finally, the www script starts the server listening on the port we specified.
Let's now walk through app.js in more detail:
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
This tells Express to look for templates in the views directory and to use the EJS templating engine.
The app.set function is used for setting application properties. It'll be useful to browse the API documentation as we go through (http://expressjs.com/en/4x/api.html).
Next is a series of app.use calls:
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
The app.use function mounts middleware functions. This is an important piece of Express jargon we will discuss shortly. At the moment, let's say that middleware functions are executed during the processing of routes. This means all the features named here are enabled in app.js:
- Logging is enabled using the Morgan request logger. Visit https://www.npmjs.com/package/morgan for its documentation.
- The body-parser module handles parsing HTTP request bodies. Visit https://www.npmjs.com/package/body-parser for its documentation.
- The cookie-parser module is used to parse HTTP cookies. Visit https://www.npmjs.com/package/cookie-parser for its documentation.
- A static file web server is configured to serve the asset files in the public directory.
- Two router modules, routes and users, to set up which functions handle which URLs.