A los ingenieros que intentaron usar el motor de plantillas de Jade y no pueden comenzar

Cuando comencé a trabajar en Storify como ingeniero de Node.js. La pila tecnológica era Express y Jade. Odio admitirlo, ¡pero luché mucho con Jade!

Antes, trabajaba principalmente con Underscore y Handlebars. Intenté modificar algo de HTML en las plantillas de Jade. Otras veces solo cambiaría el texto. Esas fueron actualizaciones triviales, pero muy a menudo hacen que todo el servidor se bloquee .

Estaba fallando miserablemente en aprender por ensayo y error. Odiaba a Jade. También estaba empezando a odiar la edición de plantillas. Entonces tuve un momento de bombilla:necesito un tutorial. Fui a los documentos oficiales. Ojalá este artículo existiera en ese momento. Después de pasar solo una hora aprendiendo Jade, pude usar Jade y hacer todos los cambios en las plantillas sin problemas.

Las personas inteligentes aprenden de sus errores y las personas sabias aprenden de los demás . No repitas mi locura. Lea este tutorial de Jade para aprovechar el poder de este maravilloso lenguaje de plantillas.

Un motor de plantillas es una biblioteca o un marco que usa algunas reglas/idiomas para interpretar datos y representar vistas. En el caso de las aplicaciones web, las vistas son páginas HTML (o partes de ellas), pero pueden ser archivos JSON o XML o, en programas de escritorio, GUI. Para aquellos que estén familiarizados con el concepto de modelo, vista y controlador, las plantillas pertenecen a la vista.

En las aplicaciones web, es beneficioso usar plantillas porque podemos generar una cantidad infinita de páginas dinámicamente con una sola plantilla. Otro beneficio secundario es cuando necesitamos cambiar algo; podemos hacerlo en un solo lugar.

Si volvemos a los diagramas del capítulo anterior (enfoque tradicional frente a API REST), podemos deducir que las plantillas se pueden compilar en HTML ya sea del lado del servidor (enfoque tradicional) o del lado del cliente (enfoque API REST). Independientemente del enfoque que adoptemos, la sintaxis de las bibliotecas permanece intacta.

En este artículo, cubriré lo siguiente:

  • Sintaxis y funciones de Jade
  • Uso independiente de Jade

Sintaxis y características de Jade

Jade es un hermano de Node.js de Haml, en el sentido de que usa espacios en blanco y sangría como parte de su lenguaje. Por lo tanto, debemos tener cuidado de seguir la sintaxis adecuada.

Puede seguir los ejemplos de sintaxis de Jade en esta sección, en línea, en la página de demostración del sitio web oficial (http://jade-lang.com/demo) o en el recurso @naltatis (http://naltatis.github.io/ jade-syntax-docs/), o escribiendo secuencias de comandos independientes de Node.js (los ejemplos se presentan en "Uso independiente de Jade", que aparece más adelante en este capítulo).

Etiquetas

Cualquier texto al comienzo de una línea, de forma predeterminada, se interpreta como una etiqueta HTML. La principal ventaja de Jade es que este texto presenta etiquetas de cierre y apertura para el elemento HTML, así como el <></> simbolos Por lo tanto, ¡nos ahorramos muchas pulsaciones de teclas como desarrolladores escribiendo en Jade!

El texto que sigue a una etiqueta y un espacio (por ejemplo, tag <text> ) se analiza como el HTML interno (es decir, contenido dentro del elemento). Por ejemplo, si tenemos el siguiente código Jade:

Body
  div
    h1 Practical Node.js
    p The only book most people will ever need.
  div
    footer &copy; Apress

El resultado de la plantilla anterior será:

<body>
  <div>
    <h1>Practical Node.js</h1>
    <p>The only book most people will ever need.</p>
  </div>
  <div>
    <footer>&copy; Apress</footer>
  </div>
</body>

Variables/Locales

Los datos que se pasan a la plantilla de Jade se denominan locales . Para generar el valor de una variable, use = . Vea los siguientes ejemplos:

[Nota al margen]

Leer publicaciones de blog es bueno, pero ver cursos en video es aún mejor porque son más atractivos.

Muchos desarrolladores se quejaron de la falta de material de video de calidad asequible en Node. Es una distracción ver videos de YouTube y una locura pagar $ 500 por un curso de video de Node.

Visite Node University, que tiene cursos de video GRATUITOS en Node:node.university.

[Fin de la nota al margen]

Código de jade:

h1= title
p= body

Locales:

{
  title: "Express.js Guide",
  body: "The Comprehensive Book on Express.js"
}

Salida HTML:

<h1>Express.js Guide</h1>
<p>The Comprehensive Book on Express.js</p> 

Atributos

Los atributos se agregan poniéndolos entre paréntesis justo después del nombre de la etiqueta. Siguen name=value formato. Además, varios atributos deben estar separados por una coma. Por ejemplo,

div(id="content", class="main")
  a(href="http://expressjsguide.com", title="Express.js Guide", target="_blank") Express.js Guide
  form(action="/login")
    button(type="submit, value="save")
div(class="hero-unit") Lean Node.js!

se convierte en:

<div id="content" class="main"><a href="http://expressjsguide.com" title="Express.js Guide"
target="_blank">Express.js Guide</a>
  <form action="/login">
    <button type="submit" value="save"></button>
  </form>
  <div class="hero-unit">Learn Node.js</div>
</div>

A veces, el valor de un atributo debe ser dinámico. En este caso, ¡simplemente use el nombre de la variable! La tubería, o | , nos permite escribir el contenido del nodo HTML en la nueva línea; en otras palabras, la línea con la tubería se convierte en texto interno. Un ejemplo es el siguiente:

a(href=url, data-active=isActive)
label
  input(type="checkbox", checked=isChecked)
  | yes / no

La plantilla anterior se proporciona con locales:

{
  url: "/logout",
  isActive: true,
  isChecked: false
}

Y ambos, es decir, la plantilla y los datos locales, producen resultados:

<a href="/logout" data-active="data-active"></a>
<label>
  <input type="checkbox"/>yes / no
</label>

Tenga en cuenta que el atributo con el valor false se omite de la salida HTML. Sin embargo, cuando no se pasa ningún valor, true se asume, por ejemplo:

input(type='radio', checked)
input(type='radio', checked=true)
input(type='radio', checked=false)
<input type="radio" checked="checked"/>
<input type="radio" checked="checked"/>
<input type="radio"/>

Literales

Para mayor comodidad, podemos escribir clases e ID justo después de los nombres de las etiquetas. Por ejemplo, podemos aplicar lead y center clases a un párrafo, y crea un div elemento con el side-bar DNI y pull-right clase (nuevamente, la tubería significa un texto interno):

div#content
  p.lead.center
    | webapplog: where code lives
    #side-bar.pull-right
    span.contact.span4
      a(href="/contact") contact us
<div id="content">
  <p class="lead center">
    webapplog: where code lives
    <div id="side-bar" class="pull-right"></div>
    <span class="contact span4">
      <a href="/contact">contact us</a>
    </span>
  </p>
</div>

Tenga en cuenta que si se omite el nombre de la etiqueta, div se usa en su lugar.

Texto

La salida de texto sin formato se realiza a través de |—por ejemplo:

div
  | Jade is a template engine.
  | It can be used in Node.js and in the browser JavaScript.

Script y bloques de estilo

A veces, los desarrolladores quieren escribir fragmentos de contenido para script o style etiquetas en el HTML! Esto es posible con un punto. Por ejemplo, podemos escribir JavaScript de interfaz de usuario en línea como este:

script.
   console.log('Hello Jade!')
   setTimeout(function(){
    window.location.href='http://rpjs.co'
   },200))
   console.log('Good bye!')
<script>
  console.log('Hello Jade!')
  setTimeout(function(){
   window.location.href='http://rpjs.co'
  },200))
  console.log('Good bye!')
</script> 

Código JavaScript

Al contrario del ejemplo anterior, si queremos usar any JavaScript en el momento de la compilación de la plantilla; en otras palabras, para escribir un código JavaScript ejecutable que manipule la salida de Jade (es decir, HTML), podemos usar el - , = , o != simbolos Esto puede ser útil cuando generamos elementos HTML e inyectamos JavaScript. Obviamente, este tipo de cosas deben hacerse con cuidado para evitar ataques de secuencias de comandos entre sitios (XSS). Por ejemplo, si queremos definir una matriz y generar <> símbolos, podemos usar != .

- var arr = ['<a>','<b>','<c>']
ul
  - for (var i = 0; i< arr.length; i++)
    li
      span= i
      span!="unescaped: " + arr[i] + " vs. "
      span= "escaped: " + arr[i]

produce esto:

<ul>
  <li><span>0</span><span>unescaped: <a> vs. </span><span>escaped: &lt;a&gt;</span></li>
  <li><span>1</span><span>unescaped: <b> vs. </span><span>escaped: &lt;b&gt;</span></li>
  <li><span>2</span><span>unescaped: <c> vs. </span><span>escaped: &lt;c&gt;</span></li>
</ul>

Consejo Una de las principales diferencias entre Jade y Handlebars es que el primero permite prácticamente cualquier JavaScript en su código, mientras que el segundo restringe a los programadores a solo un puñado de ayudantes integrados y registrados de forma personalizada.

Comentarios

Cuando se trata de comentarios, tenemos la opción de mostrarlos o no. Para el primero, use el estilo de JavaScript //; para este último, use //- . Por ejemplo,

// content goes here
p Node.js is a non-blocking I/O for scalable apps.
//- @todo change this to a class
p(id="footer") Copyright 2014 Azat

salidas:

<!-- content goes here-->
<p>Node.js is a non-blocking I/O for scalable apps.</p>
<p id="footer">Copyright 2014 Azat</p>

Condiciones (si)

Curiosamente, además del código JavaScript estándar donde el if La declaración se puede usar con el prefijo - , podemos usar una alternativa Jade minimalista sin prefijo ni paréntesis, por ejemplo:

- var user = {}
- user.admin = Math.random()>0.5
if user.admin
    button(class="launch") Launch Spacecraft
else
    button(class="login") Log in

También hay a menos que sea equivalente a not o ! .

Iteraciones (cada ciclo)

Similar a las condiciones, los iteradores en Jade se pueden escribir simplemente con each— por ejemplo:

- var languages = ['php', 'node', 'ruby']
div
  each value, index in languages
    p= index + ". " + value

La salida HTML es la siguiente:

<div>
  <p>0. php</p>
  <p>1. node</p>
  <p>2. ruby</p>
</div>

La misma construcción también funciona con objetos:

- var languages = {'php': -1, 'node': 2, 'ruby':1}
div
  each value, key in languages
    p= key + ": " + value

El Jade anterior se compila en la salida HTML:

<div>
  <p>php: -1</p>
  <p>node: 2</p>
  <p>ruby: 1</p>
</div>

Filtros

Los filtros se utilizan cuando hay bloques de textos escritos en un idioma diferente. Por ejemplo, el filtro para Markdown se ve así:

p
 :markdown
   # Practical Node.js

Este libro (http://expressjsguide.com), realmente ayuda a comprender muchos componentes necesarios para el desarrollo web moderno.

■ Nota Aún es necesario instalar los módulos Markdown. El marked y los paquetes Markdown NPM a menudo se usan para esto. No hay necesidad de una configuración adicional, simplemente instálelos en el node_modules local del proyecto carpeta.

Interpolación

La interpolación en Jade se logra a través de #{name} . Por ejemplo, para generar title en un párrafo, haga lo siguiente:

- var title = "Express.js Guide"
p Read the #{title} in PDF, MOBI and EPUB

La interpolación se procesa en la compilación de la plantilla; por lo tanto, no lo use en JavaScript ejecutable (- ).

Caso

Aquí hay un ejemplo del case declaración en Jade:

- var coins = Math.round(Math.random()*10)
case coins
  when 0
    p You have no money
  when 1
    p You have a coin
default
  p You have #{coins} coins!

Mezclas

Los mixins son funciones que toman parámetros y producen algo de HTML. La sintaxis de la declaración es mixin name(param,param2,...) , y el uso es +name(data) . Por ejemplo:

mixin row(items)
  tr
    each item, index in items
      td= item 

mixin table(tableData)
  table
    each row, index in tableData
      +row(row)
- var node = [{name: "express"}, {name: "hapi"}, {name: "derby"}]
+table(node)
- var js = [{name: "backbone"}, {name: "angular"}, {name: "ember"}]
+table(js)

La plantilla y los datos anteriores producen este HTML:

<table>
  <tr>
    <td>express</td>
  </tr>
  <tr>
    <td>hapi</td>
  </tr>
  <tr>
    <td>derby</td>
  </tr>
</table>
<table>
  <tr>
    <td>backbone</td>
  </tr>
  <tr>
    <td>angular</td>
  </tr>
  <tr>
    <td>ember</td>
  </tr>
</table>

Incluir

include es una forma de dividir la lógica en un archivo separado con el fin de reutilizarla en varios archivos. Es un enfoque de arriba hacia abajo; nosotros dictamos qué usar en el archivo que incluye otro archivo. El archivo que incluye se procesa primero (podemos definir locales allí), luego se procesa el archivo incluido (podemos usar locales definidos anteriormente).

Para incluir una plantilla de Jade, use include /path/filename. Por ejemplo, en el archivo A:

include ./includes/header

Tenga en cuenta que no es necesario usar comillas simples o dobles para el nombre de la plantilla y su ruta. Es posible atravesar el árbol:

include ../includes/footer

Pero no hay forma de usar un valor dinámico para el archivo y la ruta (usar una variable), porque las inclusiones/parciales se manejan en la compilación (no en el tiempo de ejecución).

Extender

extend es un enfoque de abajo hacia arriba (a diferencia de include ), en el sentido de que el archivo incluido ordena qué partes del archivo principal desea reemplazar. La forma en que funciona es con extender filename y block blockname declaraciones:

En file_a :

block header
  p some default text
block content
  p Loading ...
block footer
  p copyright

En file_b :

extend file_a
block header
  p very specific text
block content
  .main-content

Uso independiente de jade

Los motores de plantillas no siempre se usan con Node.js (y marcos como Express.js). A veces, es posible que solo queramos usar Jade de manera independiente. Los casos de uso incluyen la generación de una plantilla de correo electrónico, la precompilación de Jade antes de la implementación y la depuración. En esta sección, hacemos lo siguiente:

  • Instalar un módulo Jade
  • Cree nuestro primer archivo Jade
  • Cree un programa Node.js que use el archivo Jade
  • Comparar jade.compile , jade.render y jade.renderFile

Para agregar un jade dependencia a su proyecto, o si está comenzando desde cero desde una carpeta de proyecto vacía, haga lo siguiente:

  • Cree un node_modules vacío carpeta con $ mkdir node_modules
  • Instalar y agregar jade a package.json con $ npm install jade –save . Vea los resultados en la Figura 4–1.

Figura 4–1. Instalando Jade

Digamos que tenemos un script de Node.js que envía correos electrónicos y necesitamos usar una plantilla para generar HTML dinámicamente para correos electrónicos. Así es como podría verse (archivo jade-example.jade ):

.header
  h1= title
  p
.body
  p= body
.footer
  div= By
    a(href="http://twitter.com/#{author.twitter}")= author.name
ul
  each tag, index in tags
    li= tag

En este caso, nuestro script de Node.js debe hidratar o completar esta plantilla con los siguientes datos:

  • título:cadena
  • cuerpo:cadena
  • autor:cadena
  • etiquetas:matriz

Podemos extraer estas variables de múltiples fuentes (bases de datos, sistemas de archivos, entrada del usuario, etc.). Por ejemplo, en el jade-example.js archivo, usamos valores codificados para title , author , tags , pero pase a través de un argumento de línea de comando para body :

var jade = require('jade'),
  fs = require('fs'); 
var data = {
  title: "Practical Node.js",
  author: {
    twitter: "@azat_co",
    name: "Azat"
  },
  tags: ['express', 'node', 'javascript']
}
data.body = process.argv[2];

fs.readFile('jade-example.jade', 'utf-8', function(error, source){
  var template = jade.compile(source);
  var html = template(data)
  console.log(html)
});

De esta forma, cuando ejecutamos $ node jade-example.js 'email body' , obtenemos el resultado que se muestra en la Figura 4–2 .

Figura 4–2. El resultado de la salida de ejemplo de jade

La salida HTML "embellecida" es la siguiente:

<div class="header">
    <h1>Practical Node.js</h1>
    <p></p>
</div>
<div class="body">
    <p>email body</p>
</div> 
<div class="footer">
    <div><a href="http://twitter.com/@azat_co"> Azat</a>
    </div>
    <ul>
        <li>express</li>
        <li>node</li>
        <li>javascript</li>
    </ul>
</div>

Además de jade.compile() , la API de Jade tiene las funciones jade.render() y jade.renderFile() . Por ejemplo, el archivo anterior se puede reescribir con jade.render() :

var jade = require('jade'),
  fs = require('fs');

var data = {
  title: "Practical Node.js",
  author: {
    twitter: "@azat_co",
    name: "Azat"
  },
  tags: ['express', 'node', 'javascript']
}
data.body = process.argv[2];

//jade.render
fs.readFile('jade-example.jade', 'utf-8', function(error, source){
  var html = jade.render(source, data)
  console.log(html)
});

Además, con jade.renderFile , el jade-example.js file es aún más compacto:

var jade = require('jade'),
  fs = require('fs');

var data = {
  title: "Practical Node.js",
  author: {
    twitter: "@azat_co",
    name: "Azat"
  },
  tags: ['express', 'node', 'javascript']
}
data.body = process.argv[2];

//jade.renderFile

jade.renderFile('jade-example.jade', data, function(error, html){
  console.log(html)
});

Nota Jade también se puede usar como una herramienta de línea de comandos después de instalarlo con el -g o --global opción a través de NPM. Para obtener más información, ejecute jade -h o consulte la documentación oficial (http://jade-lang.com/command-line/).

Para usar Jade en un navegador, puede usar browserify (https://github.com/substack/node-browserify) y su middleware jadeify (https://github.com/substack/node-jadeify).

Nota Para usar las mismas plantillas de Jade en el front-end (navegador) y en el servidor, recomiendo jade-browser  (https://www.npmjs.org/package/jade-browser) de Storify, del cual fui el mantenedor durante un tiempo durante mi trabajo allí. jade-browser actúa como un middleware Express.js y expone plantillas del lado del servidor al navegador junto con funciones de utilidad útiles. GitHub: ttps://github.com/storify/jade-browser.

Esto termina esta guía rápida sobre Jade. En las próximas publicaciones, cubriré temas relacionados:

  • Sintaxis de manillares
  • Uso independiente del manillar
  • Uso de Jade y Handlebars en Express.js 4
  • Proyecto:agregar plantillas de Jade al Blog