Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error: Unknown template object: string when using a precompiled template with .template() #922

Closed
ricardograca opened this issue Dec 12, 2014 · 4 comments

Comments

@ricardograca
Copy link

I'm trying to register a partial, which according to the docs should be done like this:

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

handlebars.registerPartial('stuff', template)

However the .template() method produces this error:

Error: Unknown template object: string

I can see that the compiledPartial above is indeed a string that looks like an object:

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

WTF?

Node 0.10.25, Handlebars 2.0.0

@kpdecker
Copy link
Collaborator

The precompiler method is intended for serializing the template and then the template method is used to restore it on the client. If you are trying to evaluate the template in the same process then you should use Handlebars.compile directly.

@ricardograca
Copy link
Author

Thanks for the answer. It seems the docs are more geared towards using Handlebars in the client side, since it is possible to pass just the uncompiled partial string to the registerPartial() method, if you're only using Handlebars on the server side.

@jacobq
Copy link

jacobq commented Jan 28, 2015

I am writing a server-side application that needs to be able to both precompile templates (and then deliver them to the client in case they need to be re-rendered with new context) and also render them to HTML (for less noticeable flicker/delay on the client + improved SEO). It seems I either need to call both precompile and compile separately or I need to eval the serialized precompiler output. Neither of those approaches feels very elegant, so am I missing something or is my application just unusual? (BTW, this application is written in Java but using the built-in [Rhino/Nashorn] JavaScript engine for the templating portion; hopefully that doesn't matter.)

In case anyone else got confused by the documentation for precompile and wound up here, I've written an example to illustrate what is going on. (Actually, I wrote it because I was trying to figure it out what I was doing wrong.)

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)");
});

@kpdecker
Copy link
Collaborator

kpdecker commented Feb 4, 2015

@jacobq you'll want to call compile and precompile. The generated code for the two is very different and I wouldn't presume that trying to toString or similar will work with the compile output, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants