Handlebars.js: Erreur : objet modèle inconnu : chaîne lors de l'utilisation d'un modèle précompilé avec .template()

Créé le 12 déc. 2014  ·  4Commentaires  ·  Source: handlebars-lang/handlebars.js

J'essaie d'enregistrer un partiel, ce qui, selon la documentation, devrait être fait comme ceci :

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

handlebars.registerPartial('stuff', template)

Cependant, la méthode .template() produit cette erreur :

Error: Unknown template object: string

Je peux voir que le compiledPartial ci-dessus est bien une chaîne qui ressemble à un objet :

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

WTF ?

Noeud 0.10.25, Guidon 2.0.0

Commentaire le plus utile

J'écris une application côté serveur qui doit être capable à la fois de précompiler les modèles (puis de les livrer au client au cas où ils auraient besoin d'être restitués avec un nouveau contexte) et de les rendre également au format HTML (pour un scintillement/ retard sur le client + SEO amélioré). Il semble que j'aie besoin d'appeler à la fois precompile et compile séparément ou j'ai besoin de eval la sortie du précompilateur sérialisé. Aucune de ces approches ne semble très élégante, alors est-ce que j'ai raté quelque chose ou mon application est-elle simplement inhabituelle ? (BTW, cette application est écrite en Java mais utilise le moteur JavaScript intégré [Rhino/Nashorn] pour la partie de création de modèles ; espérons que cela n'a pas d'importance.)

Au cas où quelqu'un d'autre serait confus par la documentation pour la précompilation et se retrouverait ici, j'ai écrit un exemple pour illustrer ce qui se passe. (En fait, je l'ai écrit parce que j'essayais de comprendre ce que je faisais 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)");
});

Tous les 4 commentaires

La méthode precompiler est destinée à sérialiser le modèle, puis la méthode template est utilisée pour le restaurer sur le client. Si vous essayez d'évaluer le modèle dans le même processus, vous devez utiliser directement Handlebars.compile .

Merci d'avoir répondu. Il semble que les documents soient plus orientés vers l'utilisation de Handlebars côté client, car il est possible de ne transmettre que la chaîne partielle non compilée à la méthode registerPartial() , si vous n'utilisez que Handlebars côté serveur.

J'écris une application côté serveur qui doit être capable à la fois de précompiler les modèles (puis de les livrer au client au cas où ils auraient besoin d'être restitués avec un nouveau contexte) et de les rendre également au format HTML (pour un scintillement/ retard sur le client + SEO amélioré). Il semble que j'aie besoin d'appeler à la fois precompile et compile séparément ou j'ai besoin de eval la sortie du précompilateur sérialisé. Aucune de ces approches ne semble très élégante, alors est-ce que j'ai raté quelque chose ou mon application est-elle simplement inhabituelle ? (BTW, cette application est écrite en Java mais utilise le moteur JavaScript intégré [Rhino/Nashorn] pour la partie de création de modèles ; espérons que cela n'a pas d'importance.)

Au cas où quelqu'un d'autre serait confus par la documentation pour la précompilation et se retrouverait ici, j'ai écrit un exemple pour illustrer ce qui se passe. (En fait, je l'ai écrit parce que j'essayais de comprendre ce que je faisais 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 vous voudrez appeler compiler et précompiler. Le code généré pour les deux est très différent et je ne présume pas qu'essayer de toString ou similaire fonctionnera avec la sortie de compilation, etc.

Cette page vous a été utile?
0 / 5 - 0 notes