Handlebars.js: Error: objeto de plantilla desconocido: cadena cuando se usa una plantilla precompilada con .template ()

Creado en 12 dic. 2014  ·  4Comentarios  ·  Fuente: handlebars-lang/handlebars.js

Estoy tratando de registrar un parcial, que de acuerdo con los documentos debería hacerse así:

var partialString = fs.readFileSync(filename), {encoding: 'utf8'})
var compiledPartial = handlebars.precompile(partialString)
var template = handlebars.template(compiledPartial)

handlebars.registerPartial('stuff', template)

Sin embargo, el método .template() produce este error:

Error: Unknown template object: string

Puedo ver que el compiledPartial arriba es de hecho una cadena que parece un objeto:

{"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
return "<div>Stuff</div>\n";
},"useData":true}

WTF?

Nodo 0.10.25, manillares 2.0.0

Comentario más útil

Estoy escribiendo una aplicación del lado del servidor que debe poder precompilar plantillas (y luego entregarlas al cliente en caso de que necesiten ser renderizadas con un nuevo contexto) y también renderizarlas en HTML (para un parpadeo menos perceptible / retraso en el cliente + SEO mejorado). Parece que necesito llamar a precompile y compile separado o necesito eval la salida del precompilador serializado. Ninguno de esos enfoques se siente muy elegante, así que ¿me estoy perdiendo algo o mi aplicación es simplemente inusual? (Por cierto, esta aplicación está escrita en Java pero usando el motor JavaScript incorporado [Rhino / Nashorn] para la parte de plantillas; con suerte, eso no importa).

En caso de que alguien más se confunda con la documentación de la precompilación y termine aquí, he escrito un ejemplo para ilustrar lo que está sucediendo. (En realidad, lo escribí porque estaba tratando de averiguar qué estaba haciendo mal).

var templateSources = {
    hi: "Hi, {{name}}.",
    bye: "Goodbye, {{name}}."
};
var compiledTemplates = {};
var serializedTemplates = {};
var deserializedTemplates = {};

Object.keys(templateSources).forEach(function(name) {
    // Use compile method to generate actual executable template (function)
    compiledTemplates[name] = Handlebars.compile(templateSources[name]);
    // Use precompile method to generate serialized JS (string)
    serializedTemplates[name] = Handlebars.precompile(templateSources[name]);
    // If we really want, we can deserialize these 
    deserializedTemplates[name] = Handlebars.template(evalPrecompiledTemplate(serializedTemplates[name]));
});

// (Yes, I know eval is dangerous)
function evalPrecompiledTemplate(s) {
    return eval("(function(){return " + s + "}());");
}

// Quick demonstration that these template functions work the same
var context = {
    name: "John Smith"
};

// Output: 
// Rendering template named hi with context: Object {name: "John Smith"}
// Hi, John Smith.(compiled)
// Hi, John Smith.(precompiled/deserialized)
// Rendering template named bye with context: Object {name: "John Smith"}
// Goodbye, John Smith.(compiled)
// Goodbye, John Smith.(precompiled/deserialized)
Object.keys(templateSources).forEach(function(name) {
  console.log("Rendering template named " + name + " with context:", context);
  console.log(compiledTemplates[name](context) + "(compiled)");
  console.log(deserializedTemplates[name](context) + "(precompiled/deserialized)");
});

Todos 4 comentarios

El método precompiler está diseñado para serializar la plantilla y luego se usa el método template para restaurarla en el cliente. Si está tratando de evaluar la plantilla en el mismo proceso, debe usar Handlebars.compile directamente.

Gracias por la respuesta. Parece que los documentos están más orientados al uso de Handlebars en el lado del cliente, ya que es posible pasar solo la cadena parcial no compilada al método registerPartial() , si solo está usando Handlebars en el lado del servidor.

Estoy escribiendo una aplicación del lado del servidor que debe poder precompilar plantillas (y luego entregarlas al cliente en caso de que necesiten ser renderizadas con un nuevo contexto) y también renderizarlas en HTML (para un parpadeo menos perceptible / retraso en el cliente + SEO mejorado). Parece que necesito llamar a precompile y compile separado o necesito eval la salida del precompilador serializado. Ninguno de esos enfoques se siente muy elegante, así que ¿me estoy perdiendo algo o mi aplicación es simplemente inusual? (Por cierto, esta aplicación está escrita en Java pero usando el motor JavaScript incorporado [Rhino / Nashorn] para la parte de plantillas; con suerte, eso no importa).

En caso de que alguien más se confunda con la documentación de la precompilación y termine aquí, he escrito un ejemplo para ilustrar lo que está sucediendo. (En realidad, lo escribí porque estaba tratando de averiguar qué estaba haciendo mal).

var templateSources = {
    hi: "Hi, {{name}}.",
    bye: "Goodbye, {{name}}."
};
var compiledTemplates = {};
var serializedTemplates = {};
var deserializedTemplates = {};

Object.keys(templateSources).forEach(function(name) {
    // Use compile method to generate actual executable template (function)
    compiledTemplates[name] = Handlebars.compile(templateSources[name]);
    // Use precompile method to generate serialized JS (string)
    serializedTemplates[name] = Handlebars.precompile(templateSources[name]);
    // If we really want, we can deserialize these 
    deserializedTemplates[name] = Handlebars.template(evalPrecompiledTemplate(serializedTemplates[name]));
});

// (Yes, I know eval is dangerous)
function evalPrecompiledTemplate(s) {
    return eval("(function(){return " + s + "}());");
}

// Quick demonstration that these template functions work the same
var context = {
    name: "John Smith"
};

// Output: 
// Rendering template named hi with context: Object {name: "John Smith"}
// Hi, John Smith.(compiled)
// Hi, John Smith.(precompiled/deserialized)
// Rendering template named bye with context: Object {name: "John Smith"}
// Goodbye, John Smith.(compiled)
// Goodbye, John Smith.(precompiled/deserialized)
Object.keys(templateSources).forEach(function(name) {
  console.log("Rendering template named " + name + " with context:", context);
  console.log(compiledTemplates[name](context) + "(compiled)");
  console.log(deserializedTemplates[name](context) + "(precompiled/deserialized)");
});

@jacobq querrás llamar a compilar y precompilar. El código generado para los dos es muy diferente y no presumiría que intentar toString o similar funcionará con la salida de compilación, etc.

¿Fue útil esta página
0 / 5 - 0 calificaciones