Using Handlebars with Hapi


hapi nodejs Tutorials

Hello! If you are from Ukraine, Belarus, Poland or India and looking for a job in Software Development, please reach me out by email.

This tutorial is compatible with hapi v17. Node and Hapi should be installed for work with this tutorial.

In Hapi we can use different template engines to achieve dynamic HTML with dynamic data. One of this engines - Handlebars. In this tutorial we will learn how to use handlebars with Hapi framework.

Setup the server

Let’s start our work from creating a basic server in index.js file:

'use strict';

const Hapi = require('hapi');

const server = Hapi.server({
    port: 3000,
    host: 'localhost'
});

const init = async () => {
    server.route({
        method: 'GET',
        path: '/index',
        handler: (req, h) => {
            return "Hi!"
        }
    });
    await server.start();
    console.log(`Server running at: ${server.info.uri}`);
};

process.on('unhandledRejection', (err) => {
    console.log(err);
    process.exit(1);
});

init();

Setup Vision

Hapi provides Vision plugin to work with template engines. It adds additional methods to h response object. We should install it using the NPM or YARN:

npm i vision -s // or
yarn add vision

Setup Handlebars

To use Handlebars we can install it using the next command:

npm i hbs -s // or
yarn add hbs

Server configuration

To start work with handlebars, we have to require the Handlebars and Vision module:

const Vision = require('vision');
const hbs = require('hbs');

Now, let’s notify Hapi server, that we will use the Handlebars as a default template engine for our server. Using the server.views() method we can say to server, what template engine we have to use and where our templates should be located. Change the init() ****method inside index.js to the following:

'use strict';

const Hapi = require('hapi');

const server = Hapi.server({
    port: 3000,
    host: 'localhost'
});

const init = async () => {
    await server.register(Vision);
    server.views({
        engines: {
            html: hbs
        },
        relativeTo: __dirname,
        path: 'templates'
    });
    server.route({
        method: 'GET',
        path: '/index',
        handler: (req, h) => {
            return "Hi!"
        }
    });
    await server.start();
    console.log(`Server running at: ${server.info.uri}`);
};

process.on('unhandledRejection', (err) => {
    console.log(err);
    process.exit(1);
});

init();

We successfully registered handlebars as a default view engine for our Hapi server and told our server that templates are in templates folder (it should be on same level as index.js).

Go to your project folder and create a templates directory. Put an index.html template file in the templates/ folder:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible"
          content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div class="entry">
        <h1>{{title}}</h1>
        <div class="body">
            {{message}}
        </div>
    </div>
</body>
</html>

As you see, we created some variables in our index.html - the title and message. We will interpolate these variables inside GET /index route. Hapi framework provides two ways for rendering a view.

Rendering a view using .view()

In this case, we can use the view method of Vision module inside the h object. The first argument it’s the name of our template, the second argument - the data for interpolation in selected template.
GET /index route should look like this:

server.route({
    method: 'GET',
    path: '/index',
    handler: (req, h) => {
        return h.view('index', {
            title: 'Using handlebars in Hapi',
            message: 'Tutorial'
        });
    }
});

Rendering a view using view handler

In previous case, we can add additional logic/code inside handler function. If we only need to render template and nothing extra, we can change the handler from function to object and pass the view parameter. It’s called “view handler” and should look like this:

server.route({
    method: 'GET',
    path: '/index',
    handler: {
        view: {
            template: 'index',
            context: {
                title: 'Using handlebars in Hapi',
                message: 'Tutorial'
            }
        }
    }
});

To make “view handler” works you need to install the Inert module, require and register it in index.js.

The full example

'use strict';

const Hapi = require('hapi');
const Vision = require('vision');
const hbs = require('hbs');
const Inert = require('inert');

const server = Hapi.server({
    port: 3000,
    host: 'localhost'
});

const init = async () => {
    await server.register(Inert);
    await server.register(Vision);

    server.views({
        engines: {
            html: hbs
        },
        relativeTo: __dirname,
        path: 'templates'
    });

    // you need to leave only one route - view handler OR h.view, because its reproduces a conflict
    // view handler
    server.route({
        method: 'GET',
        path: '/index',
        handler: {
            view: {
                template: 'index',
                context: {
                    title: 'Using handlebars in Hapi',
                    message: 'Tutorial'
                }
            }
        }
    });

    // h.view
    server.route({
        method: 'GET',
        path: '/index',
        handler: (req, h) => {
            return h.view('index', {
                title: 'Using handlebars in Hapi',
                message: 'Tutorial'
            });
        }
    });

    await server.start();
    console.log(`Server running at: ${server.info.uri}`);
};

process.on('unhandledRejection', (err) => {
    console.log(err);
    process.exit(1);
});

init();

More information about View in Hapi: https://hapijs.com/tutorials/views

Learning Hapi.js? Buy my Hapi.js Handbook🔥

comments powered by Disqus