Skip to content

Tutorial #2: Hello World

Ardaglash edited this page Apr 7, 2021 · 8 revisions

This continues from Part 0 and Part 1 of the tutorial track.

Credit goes to Christopher Buecheler for his April 2018 version of The Dead-Simple Step-By-Step Guide for Front-End Developers to Getting Up and Running With Node.JS, Express, and MongoDB - the content below is his text and content tweaked in places for Scoutradioz specifics.

Part II – OK, Fine, let's do "Hello, World!"

Fire up Visual Studio Code. Point it at your tutorial directory and open app.js. This is kind of the heart of your, well, app. Not a big surprise there. Here's a breakdown of what you're going to see (after the changes in Part 1):

C:\node\tutorial\app.js

var e = require('@firstteam102/http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var log4js = require('log4js');

//log4js config
var log4jsConfig = {
    appenders: { out: { type: 'stdout', layout: {
        type: 'pattern',
        //Non-colored pattern layout (default)
        pattern: '[%x{tier}] [%p] %c.%x{funcName} - %m',
        tokens: {
            'tier': logEvent => {
                if (process.env.ALIAS) return process.env.ALIAS;
                else return 'LOCAL|' + process.env.TIER;
            },
            'funcName': logEvent => {
                if (logEvent.context && logEvent.context.funcName) {
                    return logEvent.context.funcName;
                }
                else return '';
            },
        },
    } } },
    categories: { default: { appenders: ['out'], level: 'info' } }
};
if( process.env.COLORIZE_LOGS == 'true'){
    //Colored pattern layout
    log4jsConfig.appenders.out.layout.pattern = '%[[%d{hh:mm:ss}] [%x{tier}] [%p] %c.%x{funcName} - %]%m';
}
log4js.configure(log4jsConfig);

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

This creates a bunch of basic JavaScript variables and ties them to certain packages, dependencies, node functionality, and routes. Routes are kind of like controllers in this setup – they direct traffic and also contain some programming logic (you can establish a more traditional MVC architecture with Express if you like. That's outside of the scope of this article). Back when we set up this project, Express created all of this stuff for us. We're going to totally ignore the user route for now and just work in the top level route (controlled by c:\node\tutorial\routes\index.js).

C:\node\tutorial\app.js

var app = express();

This one's important. It instantiates Express and assigns our app variable to it. The next section uses this variable to configure a bunch of Express stuff.

C:\node\tutorial\app.js

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

This tells the app where to find its views, what engine to use to render those views (Pug), and calls a few methods to get things up and running. Note also that the final line of the second block is telling Express to serve static objects from the /public/ dir, but to make them actually seem like they're coming from the top level (it also does this with the views directory). For example, the images directory is c:\node\tutorial\public\images ... but it is accessed at http://localhost:3000/images.

That final block, the last two lines, is important. It's telling Express that requests to http://localhost:3000/ should use the index router (which is defined up near the top of the file), and requests to http://localhost:3000/users should use the users router file.

C:\node\tutorial\app.js

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(new e.NotFoundError());
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

These are error handlers for development and production (and 404's). We're not really worrying about the difference between those two right now, but basically if your app is in development mode, your errors will give you more information. Obviously you don't want to print a stack trace out on a production site that anyone on the web can see.

C:\node\tutorial\app.js

module.exports = app;

A core part of Node is that basically all modules export an object which can easily be called elsewhere in the code. Our master app exports its app object.

Now then, let's make stuff. We're not going to just stick "Hello, World!" on our index page. Instead we're going to use this as an opportunity to learn a bit more about routes and to take a look at how Pug works for putting pages together.

We're going to start by adding a new app.use directive to app.js. Find the section that looks like this:

C:\node\tutorial\app.js

app.use('/', indexRouter);
app.use('/users', usersRouter);

These directives are telling Express what route files to use. Now, normally I'd advocate setting up separate route files for different parts of your app. For example, the users route file might contain routes for adding users, deleting them, updating them, and so forth, while a new route file called "locations" might handle adding, editing, deleting and displaying location data (in an app for which that was required). For now, to keep things simple, we're going to do everything in the index router. That means you can completely ignore the /users line.

Remember that the Express scaffolding already defined the "routes" variable and pointed it at the index router. We're going to add a "helloworld" method to that router which will render a different page than the default. In your text editor, open up your routes folder, find index.js, and open it. It will look like this:

C:\node\tutorial\routes\index.js

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res) {
    res.render('index', { title: 'Express' });
});

module.exports = router;

Pretty sparse, right? Basically we're requiring our Express functionality, then attaching a "router" variable to Express's router method, then using that method when an attempt is made to HTTP get the top level directory of our website. Finally we export our router function back to our app.

We can easily clone that get function for another page, so let's do that. At the bottom of the file, just above the module.exports line, add this code:

C:\node\tutorial\routes\index.js

/* GET Hello World page. */
router.get('/helloworld', function(req, res) {
    res.render('helloworld', { title: 'Hello, World!' });
});

That's all it takes to handle routing the URI, but we don't have any actual page for res.render to … render. That's where Pug comes in. Open up your views folder, and then go ahead and open index.pug. Before you do anything else, save it as helloworld.pug (and leave index.pug as is).

Now take a look at the code:

C:\node\tutorial\views\helloworld.pug

extends layout

block content
  h1= title
  p Welcome to #{title}

This is pretty straightforward. It uses ("extends") the file layout.pug as a template, and then within the content block defined in the layout file, it sticks a header and a paragraph. Note the use of the "title" variable which we set above, in our index.js route. This means we don't even have to change the text at all in order for it to show different stuff from the home page. But let's change it anyway to:

p Hello, World! Welcome to #{title}

Save the file, go to your command prompt, and ctrl-c to kill your server if it's already running.

Now is a good time to tell you about nodemon. Normally, if you run npm start to run your server, you will have to restart the server any time you make a change to the js server code, such as app.js or the route files. But if you use Nodemon, it will detect file changes, and automatically restart whenever it detects that a server (.js) file is changed. That's why we installed Nodemon in Part 1. Now, let's run it:

C:\node\tutorial

nodemon ./bin/www

By the way, it's worth noting: Changes to Pug templates do not require a server restart, but basically whenever you change a js file, such as app.js or the route files, you'll need to restart to see changes. In Nodemon, if you want to force a restart, simply type rs in the terminal and press enter.

Note: From the Express-Generator template, the "www" script is created inside the "bin" subfolder. If you don't want to type ./bin/www every time, feel free to move it into the root. If you do, you will need to change two things to keep everything working. In www on line 7, change '../app' to './app'. And in package.json, in order to not break the npm start command, change "start": "node ./bin/www" to "start": "node ./www". In the main Scoutradioz repository, we have www in the project root as well.

SO ... with the server restarted, navigate to http://localhost:3000/helloworld and enjoy the completely asinine text that gets displayed:

Our working Hello World page!

OK! So now we've got our router routing us to our view, which we are viewing. Let's do some modeling. I'll give you a moment if you need to fix your hair or makeup. Head to Tutorial #3: Using Our Database to proceed.