Hapi.js is a small Node framework for developing back end web apps.
In this article, we’ll look at how to create back end apps with Hapi.js.
View Helpers
We can add view helpers to our app.
For example, we can write:
index.js
const Path = require('path');
const Hapi = require('@hapi/hapi');
const Hoek = require('@hapi/hoek');
const context = {
title: 'My personal site'
};
const init = async () => {
const server = new Hapi.Server({
port: 3000,
host: '0.0.0.0',
debug: { request: ['error'] }
});
await server.register(require('@hapi/vision'));
server.views({
engines: {
html: {
module: require('handlebars'),
compileMode: 'sync'
},
},
relativeTo: __dirname,
path: 'templates',
helpersPath: './templates/helpers',
context
});
server.route({
method: 'GET',
path: '/',
handler (request, h) {
return h.view('index');
}
});
await server.start();
console.log('Server running at:', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
templates/helpers/fortunes.js
module.exports = () => {
const fortunes = [
'Wanna buy a duck?',
'Say no, then negotiate.',
'Time and tide wait for no man.',
'To teach is to learn.',
'Never ask the barber if you need a haircut.',
'You will forget that you ever knew me.',
'You will be run over by a beer truck.',
'Fortune favors the lucky.',
'Have a nice day!'
];
const x = Math.floor(Math.random() * fortunes.length);
return fortunes[x];
};
We create the fortune.js
which has a function we exported.
It returns the value we want to display.
In index.html
, we interpolate the value of the helper name to displayed the returned value:
<p>{{fortune}}</p>
And then we specify the path to the template helpers with the helpersPath
property.
Now when we go to the /
page, we see a random fortune displayed.
Layouts
We can add our layouts in their own files.
For example, we can write:
index.js
const Path = require('path');
const Hapi = require('@hapi/hapi');
const Hoek = require('@hapi/hoek');
const context = {
title: 'My personal site'
};
const init = async () => {
const server = new Hapi.Server({
port: 3000,
host: '0.0.0.0',
debug: { request: ['error'] }
});
await server.register(require('@hapi/vision'));
server.views({
engines: {
html: {
module: require('handlebars'),
compileMode: 'sync'
},
},
relativeTo: __dirname,
path: 'templates',
layout: true,
layoutPath: 'templates/layout',
});
server.route({
method: 'GET',
path: '/',
handler (request, h) {
return h.view('index');
}
});
await server.start();
console.log('Server running at:', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
templates/layout/layout.html
<html>
<body>
{{{content}}}
</body>
</html>
templates/index.html
<div>Content</div>
We set the layout
property to true
to let us use layout files for layouts.
Then we set the layoutPath
to set the layout path.
In layout.html
, we have:
{{{content}}}
to display the content.
And in templates/index.html
, we have the content.
We can also specify a different layout per view.
For instance, we can write:
const Path = require('path');
const Hapi = require('@hapi/hapi');
const Hoek = require('@hapi/hoek');
const context = {
title: 'My personal site'
};
const init = async () => {
const server = new Hapi.Server({
port: 3000,
host: '0.0.0.0',
debug: { request: ['error'] }
});
await server.register(require('@hapi/vision'));
server.views({
engines: {
html: {
module: require('handlebars'),
compileMode: 'sync'
},
},
relativeTo: __dirname,
path: 'templates',
layout: true,
layoutPath: 'templates/layout',
});
server.route({
method: 'GET',
path: '/',
handler (request, h) {
return h.view('index', null, { layout: 'another_layout' });
}
});
await server.start();
console.log('Server running at:', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
templates/layout/another_layout.html
:
<html>
<body>
<b>{{{content}}}</b>
</body>
</html>
We specify the layout we want to use by writing:
h.view('index', null, { layout: 'another_layout' });
The layout
property has the name of the layout file we want to use.
Conclusion
We can render layouts and helpers in views with Hapi.