Utilizando Handlebars como Motor de Templates - Node.js
Normalmente, aplicações Express utilizam não apenas arquivos HTML padrão, mas também entidades especiais chamadas "templates", das quais são criados os arquivos HTML. A vantagem deles é que permitem a reutilização de código e a separação de responsabilidades, tornando o código mais limpo e organizado.
Um componente especial, chamada view engine(motor de visualizações), também conhecido como template engine (motor de templates), gerencia as visualizações. Existem diversos motores de visualizações no Express, como Pug, Jade, Dust, Nunjucks, EJS, Handlebars e outros. A escolha da view engine é uma questão de preferência, pois todas eles oferecem funcionalidades semelhantes, diferindo apenas em alguns detalhes.
Para trabalhar com motores de templates no Express, existem algumas configurações globais que podemos definir. A principal é a configuração do view engine
views
views
Vamos começar a trabalhar com templates usando a engine Handlebars, ou simplesmente hbs.
Para instalar o Handlebars, executamos o seguinte comando no terminal:
npm install hbs --save
Depois, criamos uma pasta chamada views
contact.hbs
.hbs
No arquivo contact.hbs
<html>
<head>
<title>Contatos</title>
<meta charset="utf-8" />
</head>
<body>
<h1>Contatos</h1>
<p>Email: admin@mycorp.com</p>
</body>
</html>
Essa visualização parece uma página web comum, mas, na verdade, ainda não é uma página HTML completa, pois não contém templates dinâmicos. O projeto deve ter a seguinte estrutura:
my-express-app/ |-- node_modules/ |-- views/ | |-- contact.hbs |-- app.js |-- package.json |-- package-lock.json
O código do arquivo app.js
const express = require("express");
const app = express();
app.set("view engine", "hbs");
app.use("/contact", function(_, response) {
response.render("contact.hbs");
});
app.use("/", function(_, response) {
response.send("Página Principal");
});
applisten(3000, () => console.log("Servidor iniciado em http://localhost:3000"));
Para configurar o Handlebars como view engine no Express, utilizamos a função:
app.set("view engine", "hbs");
Para a rota /contact
contact.hbs
response.render()
Iniciamos a aplicação e fazemos uma requisição no navegador para http://localhost:3000/contact
Isso deve exibir a página de contatos definida na visualização contact.hbs

Modelo de Visualização
Uma das vantagens dos templates é que podemos passar para as visualizações objetos especiais chamados "modelos de visualização". Esses objetos contêm dados que a view engine usa para renderizar a página.
Vamos modificar o arquivo app.js
const express = require("express");
const app = express();
app.set("view engine", "hbs");
app.use("/contact", function(_, response) {
response.render("contact.hbs", {
title: "Meus Contatos",
email: "gg@mycorp.com",
phone: "+1234567890"
});
});
app.use("/", function(_, response) {
response.send("Página Principal");
});
app.listen(3000, () => console.log("Servidor iniciado em http://localhost:3000"));
Agora, como segundo parâmetro da função response.render()
Alteramos o código da visualização contact.hbs
<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
<meta charset="utf-8" />
</head>
<body>
<h1>{{title}}</h1>
<p>Email: {{email}}</p>
<p>Telefone: {{phone}}</p>
</body>
</html>
Em vez de usar dados estáticos, o código da visualização agora utiliza os dados definidos no modelo. Para acessar as propriedades do modelo, usamos chaves duplas, como {{ title }}
Reiniciamos a aplicação e acessamos novamente o endereço http://localhost:3000/contact

Trabalhando com Arrays
Vamos considerar um caso mais complexo, onde passamos um array para a visualização. Modifique o arquivo app.js da seguinte maneira:
const express = require("express");
const app = express();
app.set("view engine", "hbs");
app.use("/contact", function(_, response) {
response.render("contact.hbs", {
title: "Meus Contatos",
emailsVisible: true,
emails: ["gg@mycorp.com", "lol@mycorp.com"],
phone: "+1234567890"
});
});
app.use("/", function(_, response) {
response.send("Página Principal");
});
app.listen(3000, () => console.log("Servidor iniciado em http://localhost:3000"));
Alteramos o código da visualização contact.hbs
<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
<meta charset="utf-8" />
</head>
<body>
<h1>{{title}}</h1>
{{#if emailsVisible}}
<h3>Emails</h3>
<ul>
{{#each emails}}
<li>{{this}}</li>
{{/each}}
</ul>
{{/if}}
<p>Telefone: {{phone}}</p>
</body>
</html>
A expressão {{#if emailsVisible}}
emailsVisible
true
{{#if emailsVisible}}
{{/if}}
Para iterar sobre arrays, usamos a construção each
{{#each emails}}
<li>{{this}}</li>
{{/each}}
Essa construção itera sobre todos os elementos do array emails e cria um elemento <li></li>
this

Alterando o Caminho para as Visualizações
Por padrão, as visualizações são colocadas na pasta views
views
const express = require("express");
const app = express();
app.set("view engine", "hbs");
app.set("views", __dirname + "/templates"); // definindo o caminho para as visualizações
app.use("/contact", function(_, response) {
response.render("contact");
});
app.listen(3000, () => console.log("Servidor iniciado em http://localhost:3000"));
Neste caso, a pasta templates