Gu铆a de manillares: motor de plantillas para Node / JavaScript

    Introducci贸n

    En este art铆culo, veremos c贸mo usar el motor de plantillas de Handlebars con Node.js y Express. Cubriremos qu茅 son los motores de plantilla y c贸mo se pueden usar Handlebars para crear aplicaciones web Server Side Rendered (SSR).

    Tambi茅n discutiremos c贸mo configurar manillares con el Express.js framework y c贸mo utilizar ayudantes integrados para crear p谩ginas din谩micas. Finalmente, veremos c贸mo desarrollar un asistente personalizado cuando sea necesario.

    驴Qu茅 es un motor de plantillas?

    En los a帽os 90, cuando se introdujo Internet en el mundo, se utilizaba principalmente con fines cient铆ficos, como la publicaci贸n de art铆culos de investigaci贸n y como canal de comunicaci贸n entre universidades y cient铆ficos. La mayor铆a de las p谩ginas web en ese entonces eran est谩ticas. Una p谩gina web est谩tica es la misma para todos los usuarios y no cambia por usuario. Si se va a cambiar algo en una p谩gina, se habr铆a hecho manualmente.

    En el mundo moderno, las cosas son mucho m谩s interactivas y se adaptan a cada usuario. Hoy, casi todo el mundo tiene acceso a Internet. La mayor铆a de las aplicaciones web actuales son din谩micas. Por ejemplo, en Facebook, usted y yo veremos feeds de noticias muy diferentes cuando inicie sesi贸n. Para cada persona, la p谩gina seguir谩 la misma plantilla (es decir, publicaciones secuenciales con nombres de usuario encima), pero el contenido ser谩 diferente.

    Este es el trabajo de un motor de plantillas: se define la plantilla para la fuente de noticias y luego, en funci贸n del usuario actual y la consulta a la base de datos, la plantilla se completa con el contenido recibido.

    Podemos usar motores de plantilla tanto en el backend como en el front-end. Si usamos un motor de plantilla en el backend para generar el HTML, lo llamamos renderizaci贸n del lado del servidor (SSR).

    Bigote daliniano

    Los manillares son populares tanto para las plantillas traseras como para las frontales. Por ejemplo, el popular framework front-end Ascua utiliza Handlebars como motor de plantillas.

    Manillar es una extensi贸n del Bigote lenguaje de plantilla, que se centra principalmente en la simplicidad y las plantillas m铆nimas.

    Usar manubrios con Node.js

    Para comenzar, cree una carpeta vac铆a, abra el s铆mbolo del sistema dentro de esa carpeta y luego ejecute npm init -y para crear un proyecto Node.js vac铆o con la configuraci贸n predeterminada.

    Antes de comenzar, debemos instalar las bibliotecas de Node.js necesarias. Puede instalar el R谩pido y manillares express m贸dulos ejecutando:

    $ npm install --save express express-handlebars
    

    Nota: Cuando use Handlebars en el lado del servidor, probablemente use un m贸dulo de ayuda como express-handlebars que integra Handlebars con tu framework web. En este art铆culo nos centraremos principalmente en la sintaxis de las plantillas, por lo que estamos usando express-handlebars, pero en caso de que est茅 manejando la compilaci贸n de la plantilla y renderiz谩ndose usted mismo, querr谩 consultar la referencia de la API de compilaci贸n tambi茅n.

    Luego, vamos a recrear la estructura de directorios predeterminada de Handlebars. los views La carpeta contiene todas las plantillas de manillares:

    .
    鈹溾攢鈹 app.js
    鈹斺攢鈹 views
        鈹溾攢鈹 home.hbs
        鈹斺攢鈹 layouts
            鈹斺攢鈹 main.hbs
    

    los layouts carpeta dentro de la views La carpeta contendr谩 los dise帽os o los envoltorios de la plantilla. Esos dise帽os contendr谩n la estructura HTML, las hojas de estilo y los scripts que se comparten entre las plantillas.

    los main.hbs archivo es el dise帽o principal. los home.hbs El archivo es un ejemplo de plantilla de manillares sobre el que vamos a construir.

    Agregaremos m谩s plantillas y carpetas a medida que continuemos.

    En nuestro ejemplo, usaremos un script para mantener esto simple. Importemos las bibliotecas necesarias en nuestro app.js archivo:

    const express = require('express');
    const exphbs = require('express-handlebars');
    

    Entonces, creemos una aplicaci贸n Express:

    const app = express();
    

    Ahora podemos configurar express-handlebars como nuestro motor de vista:

    app.engine('hbs', exphbs({
        defaultLayout: 'main',
        extname: '.hbs'
    }));
    
    app.set('view engine', 'hbs');
    

    De forma predeterminada, la extensi贸n para las plantillas de manillares es .handlebars. Pero en la configuraci贸n aqu铆, lo cambiamos a .hbs mediante el extname bandera porque es m谩s corta.

    Incluyamos el Oreja guiones y estilos en el main.hbs dise帽o:

    <html lang="en">
    <head>
        <!-- <meta> tags> -->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
        <title>Book Face</title>
    </head>
    
    <body>
        <div class="container">
            {{{body}}}
        </div>
    
        <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/[email聽protected]/dist/umd/popper.min.js"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
    </body>
    </html>
    

    Y ahora, cambiemos nuestro home.hbs para incluir un mensaje:

    <h1>Hello World from Handlebars</h1>
    

    Para poder acceder a esta p谩gina, debemos configurar un controlador de solicitudes. Pong谩moslo en la ruta ra铆z:

    app.get("https://Pharos.sh.com/", (req, res) => {
        res.render('home');
    });
    

    Finalmente, solo necesitamos comenzar a escuchar en un puerto las solicitudes:

    app.listen(3000, () => {
        console.log('The web server has started on port 3000');
    });
    

    Podemos ejecutar la aplicaci贸n con node app.js en la consola, sin embargo, tambi茅n podemos optar por utilizar una herramienta como Nodemon. Con nodemon, no necesitamos reiniciar el servidor cada vez que hacemos un cambio; cuando cambiamos el c贸digo, nodemon actualizar谩 el servidor.

    Vamos a instalarlo:

    $ npm i -g nodemon
    

    Y ejecutar la aplicaci贸n con nodemon se realiza a trav茅s de:

    $ nodemon app.js
    

    Visitemos nuestra aplicaci贸n a trav茅s del navegador:

    Con todo en su lugar, exploremos algunas caracter铆sticas de Handlebars.

    Funciones de idioma del manillar

    Para mostrar algunas de las caracter铆sticas de Handlebars, crearemos un feed de redes sociales. El feed extraer谩 datos de una matriz simple, simulando una base de datos.

    El feed contendr谩 publicaciones con im谩genes y comentarios. Si no hay comentarios en una imagen, aparecer谩 el mensaje “Sea el primero en comentar esta publicaci贸n”.

    Actualicemos nuestro home.hbs Para empezar:

    <nav class="navbar navbar-dark bg-dark">
        <a class="navbar-brand" href="#">Book Face</a>
    </nav>
    
    <div class="posts">
        <div class="row justify-content-center">
            <div class="col-lg-7" style="margin-top: 50px;">
                <div class="card">
    
                    <img src="https://picsum.photos/500/500"
                        class="card-img-top" alt="...">
                    <div class="card-body">
                        <h5 class="card-title">Posted by Janith Kasun</h5>
    
                        <ul class="list-group">
                            <li class="list-group-item">This is supposed to be a comment</li>
                            <li class="list-group-item">This is supposed to be a comment</li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    </div>
    

    Como puede ver en esta plantilla de manillares, hemos agregado un navbar y un card con algunos valores de marcador de posici贸n codificados.

    Nuestra p谩gina ahora se ve as铆:

    Pasar par谩metros a plantillas

    Ahora, eliminemos estos valores codificados de la propia p谩gina y pas茅moslos del script a la p谩gina. Estos luego ser谩n reemplazados con valores de comentario en la matriz:

    app.get("https://Pharos.sh.com/", function (req, res) {
        res.render('home', {
            post: {
                author: 'Janith Kasun',
                image: 'https://picsum.photos/500/500',
                comments: []
            }
        });
    });
    

    los post contiene campos como author, imagey comments. Podemos hacer referencia al post en nuestra plantilla Manillares {{post}}:

    <div class="posts">
        <div class="row justify-content-center">
            <div class="col-lg-7" style="margin-top: 50px;">
                <div class="card">
    
                    <img src="{{post.image}}"
                        class="card-img-top" alt="...">
                    <div class="card-body">
                        <h5 class="card-title">Posted by {{post.author}}</h5>
    
                        <ul class="list-group">
                            <li class="list-group-item">This is suppose to be a comment</li>
                            <li class="list-group-item">This is suppose to be a comment</li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    </div>
    

    Al hacer referencia a estos valores con el controlador que representa la p谩gina, se insertan en el lado del servidor y al usuario se le ofrece HTML aparentemente est谩tico con estos valores ya presentes.

    Condiciones de uso

    Como tenemos l贸gica condicional, es decir, mostrar los comentarios si est谩n presentes y un mensaje si no lo est谩n, veamos c贸mo podemos usar condicionales en las plantillas de Handlebars:

    <div class="posts">
        <div class="row justify-content-center">
            <div class="col-lg-7" style="margin-top: 50px;">
                <div class="card">
    
                    <img src="{{post.image}}" class="card-img-top" alt="...">
                    <div class="card-body">
                        <h5 class="card-title">Posted by {{post.author}}</h5>
    
                        {{#if post.comments}}
                        <ul class="list-group">
                            <!-- Display comment logic -->
    
                        </ul>
                        {{else}}
                        <ul class="list-group">
                            <li class="list-group-item">Be first to comment on this post!</li>
                        </ul>
                        {{/if}}
                    </div>
                </div>
            </div>
        </div>
    </div>
    

    Ahora, solo deber铆a ver la secci贸n “Sea el primero en comentar esta publicaci贸n” representada en su p谩gina, ya que la matriz de comentarios est谩 vac铆a:

    los #if es un ayudante integrado en Handlebars. Si la sentencia if regresa true, el bloque dentro del #if se renderizar谩 el bloque. Si false, undefined, null, "", 0o [] se devuelven, el bloque no se procesar谩.

    Nuestra matriz est谩 vac铆a ([]) para que el bloque no se procese.

    #if solo acepta una condici贸n y no puede usar la sintaxis de comparaci贸n de JavaScript (===). Si necesita utilizar varias condiciones o sintaxis adicional, puede crear una variable en el c贸digo y pasarla a la plantilla. Adem谩s, puede definir su propio ayudante, lo que haremos en la 煤ltima secci贸n.

    Usar bucles

    Dado que una publicaci贸n puede contener varios comentarios, necesitaremos un bucle para leerlos todos y representarlos. Primero llenemos nuestra matriz con algunos comentarios:

    app.get("https://Pharos.sh.com/", function (req, res) {
        res.render('home', {
            post: {
                author: 'Janith Kasun',
                image: 'https://picsum.photos/500/500',
                comments: [
                    'This is the first comment',
                    'This is the second comment',
                    'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec fermentum ligula. Sed vitae erat lectus.'
                ]
            }
        });
    });
    

    Y ahora, en nuestra plantilla, usaremos el #each bucle para revisarlos todos:

    <div class="posts">
        <div class="row justify-content-center">
            <div class="col-lg-7" style="margin-top: 50px;">
                <div class="card">
    
                    <img src="{{post.image}}" class="card-img-top" alt="...">
                    <div class="card-body">
                        <h5 class="card-title">Posted by {{post.author}}</h5>
    
                        {{#if post.comments}}
                        <ul class="list-group">
                            {{#each post.comments}}
                            <li class="list-group-item">{{this}}</li>
                            {{/each}}
                        </ul>
                        {{else}}
                        <ul class="list-group">
                            <li class="list-group-item">Be first to comment on this post</li>
                        </ul>
                        {{/if}}
                    </div>
                </div>
            </div>
        </div>
    </div>
    

    Dentro de #each bucle, puedes usar this para hacer referencia al elemento que est谩 en la iteraci贸n actual. En nuestro caso, se refiere a una cadena que luego se representa:

    Si tiene una matriz de objetos, tambi茅n puede acceder a cualquier atributo de ese objeto. Por ejemplo, si hay una variedad de personas, simplemente puede usar this.name para acceder al name campo.

    Ahora, cambiemos los par谩metros de nuestra plantilla para que contengan m煤ltiples publicaciones:

    app.get("https://Pharos.sh.com/", function (req, res) {
        res.render('home', {
            posts: [
                {
                    author: 'Janith Kasun',
                    image: 'https://picsum.photos/500/500',
                    comments: [
                        'This is the first comment',
                        'This is the second comment',
                        'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec fermentum ligula. Sed vitae erat lectus.'
                    ]
                },
                {
                    author: 'John Doe',
                    image: 'https://picsum.photos/500/500?2',
                    comments: [
                    ]
                }
            ]
        });
    });
    

    Ahora tambi茅n podemos poner un #each para recorrer las publicaciones:

    <div class="posts">
        <div class="row justify-content-center">
            {{#each posts}}
            <div class="col-lg-7" style="margin-top: 50px;">
                <div class="card">
                    <img src="{{this.image}}" class="card-img-top" alt="...">
                    <div class="card-body">
                        <h5 class="card-title">Posted by {{this.author}}</h5>
    
                        {{#if this.comments}}
                        <ul class="list-group">
                            {{#each this.comments}}
                            <li class="list-group-item">{{this}}</li>
                            {{/each}}
                        </ul>
                        {{else}}
                        <ul class="list-group">
                            <li class="list-group-item">Be first to comment on this post</li>
                        </ul>
                        {{/if}}
                    </div>
                </div>
            </div>
            {{/each}}
        </div>
    </div>
    

    Usando parcial

    Pr谩cticamente todas las p谩ginas web contienen secciones diferentes. En un nivel b谩sico, estas son las secciones Encabezado, Cuerpo y Pie de p谩gina. Dado que el encabezado y el pie de p谩gina generalmente se comparten entre muchas p谩ginas, tener esto en todas las p谩ginas web pronto se volver谩 extremadamente molesto y simplemente redundante.

    Afortunadamente, podemos usar Handlebars para dividir estas secciones en plantillas y simplemente incluir estas plantillas como “parciales” en las propias p谩ginas.

    En nuestro caso, como no tenemos pie de p谩gina, hagamos un header.hbs y un posts.hbs archivo en un partials directorio:

    .
    鈹溾攢鈹 app.js
    鈹斺攢鈹 views
        鈹溾攢鈹 home.hbs
        鈹溾攢鈹 layouts
        |  鈹斺攢鈹 main.hbs
        鈹斺攢鈹 paritials
           鈹斺攢鈹 header.hbs
           鈹斺攢鈹 posts.hbs
    

    Luego, moveremos el c贸digo del encabezado al header.hbs archivo:

    <nav class="navbar navbar-dark bg-dark">
        <a class="navbar-brand" href="#">Book Face</a>
    </nav>
    

    Y el c贸digo de alimentaci贸n en el posts.hbs archivo:

    <div class="posts">
        <div class="row justify-content-center">
            {{#each posts}}
            <div class="col-lg-7" style="margin-top: 50px;">
                <div class="card">
    
                    <img src="{{this.image}}" class="card-img-top" alt="...">
                    <div class="card-body">
                        <h5 class="card-title">Posted by {{this.author}}</h5>
    
                        {{#if this.comments}}
                        <ul class="list-group">
                            {{#each this.comments}}
                            <li class="list-group-item">{{this}}</li>
                            {{/each}}
                        </ul>
                        {{else}}
                        <ul class="list-group">
                            <li class="list-group-item">Be first to comment on this post</li>
                        </ul>
                        {{/if}}
                    </div>
                </div>
            </div>
            {{/each}}
        </div>
    </div>
    

    Y ahora, podemos incluirlos en el home.hbs archivo:

    {{>header}}
    
    {{>posts posts=posts}}
    

    El usuario no ver谩 la diferencia, pero nuestro home.hbs el archivo est谩 mucho m谩s limpio ahora. Esto se vuelve muy 煤til cuando tienes p谩ginas web complejas.

    Aqu铆, simplemente hemos incluido el header.hbs archivo y pas贸 un posts par谩metro al posts campo de la posts.hbs archivo.

    Lo que hace esto es que pasa el posts de nuestro manejador al posts par谩metro en el posts.hbs archivo de p谩gina.

    Creaci贸n de un asistente personalizado

    Como puede ver en la p谩gina, tenemos un solo comentario que consume dos l铆neas. Creemos un ayudante personalizado para resumir ese texto.

    Para ello, en la configuraci贸n de Handlebars, podemos definir nuestras funciones de ayuda. En nuestro caso, recortaremos los comentarios a 64 caracteres:

    app.engine('hbs', exphbs({
        defaultLayout: 'main',
        extname: '.hbs',
        helpers: {
            getShortComment(comment) {
                if (comment.length < 64) {
                    return comment;
                }
    
                return comment.substring(0, 61) + '...';
            }
        }
    }));
    

    Ahora usemos este ayudante en nuestro posts.hbs plantilla para resumir comentarios:

    <div class="posts">
        <div class="row justify-content-center">
            {{#each posts}}
            <div class="col-lg-7" style="margin-top: 50px;">
                <div class="card">
    
                    <img src="{{this.image}}" class="card-img-top" alt="...">
                    <div class="card-body">
                        <h5 class="card-title">Posted by {{this.author}}</h5>
    
                        {{#if this.comments}}
                        <ul class="list-group">
                            {{#each this.comments}}
                            <li class="list-group-item">{{getShortComment this}}</li>
                            {{/each}}
                        </ul>
                        {{else}}
                        <ul class="list-group">
                            <li class="list-group-item">Be first to comment on this post</li>
                        </ul>
                        {{/if}}
                    </div>
                </div>
            </div>
            {{/each}}
        </div>
    </div>
    

    Seguramente, los comentarios est谩n recortados en nuestra p谩gina ahora:

    Conclusi贸n

    En este art铆culo, cubrimos los conceptos b谩sicos de Handlebars, un motor de plantillas para Node.js y JavaScript front-end. Usando Handlebars, podemos crear p谩ginas web din谩micas que se renderizan en el lado del servidor o del cliente. Utilizando los condicionales, bucles, parciales y funciones de ayuda personalizadas de Handlebars, nuestras p谩ginas web se convierten en algo m谩s que HTML est谩tico.

    El c贸digo tambi茅n est谩 disponible en GitHub, como siempre. Tambi茅n puede encontrar m谩s informaci贸n sobre manillares en su p谩gina web oficial.

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *