2012-04-06 20 views
30

Tengo una aplicación en Node.js que usa Expressjs y manubrios como motor de plantillas.Node.js con Handlebars.js en el servidor y el cliente

Expressjs usa diseños y luego muestra vistas. La disposición (layout.hbs) tiene el siguiente aspecto:

<!doctype html> 
<html lang="en"> 
    <head> 
    </head> 
    <body> 
    {{{body}}} 
    </body> 
</html> 

la {{{body}}} se sustituye el lado del servidor, dentro de Node.js cuando accede a una ruta. Por ejemplo:

app.get('/', function(req, res){ 
    res.render('index'}) 
}) 

reemplazará la etiqueta {{{body}}} con el contenido de index.hbs.

Ahora, en el lado del cliente estoy usando Backbone.js y quiero utilizar los manubrios para las vistas controladas a través de Backbone. El problema es que debido a que estas páginas ya se procesaron a través de los manubrios, cuando intento usar manubrios dentro de él (o manubrios dentro de manubrios) no funciona. No hay errores, simplemente no reemplaza las etiquetas con datos.

¿Alguien ha encontrado esto antes o tiene alguna idea que trabajar?

Gracias!

Respuesta

13

Sí, es un problema pegajoso --- algo así como los problemas de citas en los scripts de shell que se convierten en un nido de citas entre comillas.

Mi solución es usar jade (a la haml) en expressjs (en el lado del servidor) para generar plantillas basadas en manillares para el cliente. De esta forma, el servidor usa una sintaxis (jade) y el cliente usa otra (barras de control). Estoy en la misma encrucijada que tú, así que tengo el mismo desafío.

Por supuesto, jade no es esencial (aunque está listo para expressjs). Puede elegir cualquier motor de plantilla (que no sea de manubrio) para el servidor, y/o puede usar barras de control en el servidor con plantillas que no sean del manubrio en el cliente, siempre que las dos sintaxis de sus motores de plantillas elegidos no chocar. Como estoy usando emberjs en el cliente y usa la sintaxis del manillar (de manera predeterminada), prefiero usar la sintaxis de emberjs + handlebars en el cliente. Así que expressjs + jade se convirtió en un ajuste natural para el servidor.

+0

Bastante, parece que tendré que usar un motor de plantilla diferente, ¡gracias! – dzm

+0

De nada. Feliz de ayudar. – occam

+0

Aunque usar Jade parece ser la solución, no estoy convencido. Si encuentras otra solución, estaré muy contento ... por ahora creo que usar Jade y Angular.js es mi alivio. –

11

¡Auto promoción sin vergüenza!

que quería hacer esta misma cosa/intercambio cliente-servidor, por lo que escribió un pequeño paquete de NPM para ayudar:

node-handlebars-precompiler

azoté para arriba en un par de horas basado en el comando compilador de línea en el repositorio de manillares de wycats. No es el mejor código del mundo, pero me ha hecho bien el trabajo.

EDIT: Ya no estoy manteniendo este paquete. Si desea hacerse cargo, póngase en contacto conmigo a través de Github. Principalmente uso plantillas de Jade ahora, así que no tiene sentido que continúe como mantenedor.

4

He solucionado esto pasando plantillas de cliente a través de plantillas de servidor.

Así que en el lado del servidor, lea todas las plantillas del lado del cliente en una matriz y pasarlo a su función de representar en el lado del servidor

En el controlador de ruta hacer algo como:

readTemplates(function(err, clientTemplates) { 
    res.render("page", { 
    clientTemplates: clientTemplates; 
    }); 
}); 

y después en layout.hbs:

{{#each clientTemplates}} 
<script type="text/handlebars id="{{this.filename}}" > 
{{{this.template}}} 
</script> 
{{/each}} 

Aquí estoy usando nombres de archivos sin extensiones como el identificador de la plantilla para que puedan ser referenciados desde puntos de vista backbone. Ah, y recuerda implementar el almacenamiento en caché para el modo de producción.

Sí, esto apesta.

Creo que deberíamos escribir un ayudante de Handlebars/Express/Connect para esto.

70

Debe utilizar plantillas de cliente compiladas previamente. Se ejecutan más rápido y le permiten usar el mismo lenguaje de plantilla en el servidor y el cliente.

  1. Instalar manillar a nivel mundial npm install handlebars -g
  2. Precompile sus plantillas handlebars client-template1.handlebars -f templates.js
  3. Incluir templates.js <script src="templates.js"></script>
  4. ejecutar la plantilla var html = Handlebars.templates["client-template1"](context);

https://stackoverflow.com/a/13884587/8360

+5

Esta es una solución mucho mejor que la respuesta aceptada, imo – Paul

+3

incluso más fácil ahora https://npmjs.org/package/grunt-contrib-handlebars – slf

27

Una forma sencilla de hacerlo es para solo la aplicación termine un \ antes del {{ en un archivo de manubrios. Por ejemplo:

<script type="text/x-template" id="todo-item-template"> 
<div class="todo-view"> 
    <input type="checkbox" class="todo-checkbox" \{{checked}}> 
    <span class="todo-content" tabindex="0">\{{text}}</span> 
</div> 

<div class="todo-edit"> 
    <input type="text" class="todo-input" value="\{{text}}"> 
</div> 

<a href="#" class="todo-remove" title="Remove this task"> 
    <span class="todo-remove-icon"></span> 
</a> 

El código anterior se representará en el cliente con el {{..}} etiquetas conservadas.

+0

¿De verdad? Maldición, desearía haberlo sabido hace un año. Eso es bueno y simple. –

+0

¡Funciona como un regalo, gracias! –

+1

Eso funcionó muy bien, ojalá lo hubieran puesto en la documentación ... o tal vez solo lo extrañé. – skud

1

Tiene 2 opciones. El segundo es el mejor camino a seguir:

1) escapar de los bigotes

<script type="text/x-handlebars" data-hbs="example"> 
    <p>\{{name}}</p> 
</script> 

2) precompilación

Esto compilará la plantilla en el servidor antes de que salga al cliente. Esto hará que la plantilla esté lista para usar y reduce la carga en el navegador.

0

No me gustó la solución de precompilación (porque quiero definir plantillas en el mismo archivo donde las usaré) ni la ingenua \{{ solución de escape (porque necesita el compilador completo de Handlebars y más código de JavaScript) así que ocurrió una solución híbrida que utiliza ayudantes Manillares:

1) el registro de un nuevo helper llamado 'plantilla' en la configuración del servidor

var hbs = require('hbs'); 
hbs.registerHelper("template", function(key, options){ 
    var source = options.fn().replace("\\{{", "{{"); 
    var ret = 
    '<script>\n' + 
     key + ' = function(opt){\n' + 
      'return Handlebars.template(' + hbs.handlebars.precompile(source) + ')(opt);\n' + 
     '}\n' + 
    '</script>'; 
    return ret; 
}); 


2) se usa cualquier parte de la página web del lado del cliente (con \{{ escape f o los parámetros del lado del cliente)

{{#template "myTemplate"}} 
    <div> 
     <p>Hello \{{this.name}}!</p> 
    </div> 
{{/template}} 

(el servidor precompilarla en algo como esto)

<script> 
    myTemplate = function(opt){ 
     return Handlebars.template(/* HBS PRECOMPILATED FUNCTION */)(opt); 
    } 
</script> 


3) Basta con llamar a la función en la que se necesita en el lado del cliente JavaScript

var generatedHtml = myTemplate("world"); // = <div><p>Hello world!</p></div> 
$("#myDiv").html(generatedHtml);   // or whatever 
Cuestiones relacionadas