admin管理员组

文章数量:1245119

Premise

We've got handlebars running in a backend nodejs application for templating various messages that get sent.

Handlebarspile throws this exception (when piling templates from partials)

Error: You must pass a string or Handlebars AST to Handlebarspile. You passed <html>
<head>
... extremely long markup
at Objectpile (/Users/guscrawford/rollick-management-console/deployd/node_modules/handlebars/dist/cjs/handlebars/piler/piler.js:501:11)
at HandlebarsEnvironment.hbpile (/Users/guscrawford/rollick-management-console/deployd/node_modules/handlebars/dist/cjs/handlebars.js:39:40)
at Object.invokePartialWrapper [as invokePartial] (/Users/guscrawford/rollick-management-console/deployd/node_modules/handlebars/dist/cjs/handlebars/runtime.js:71:44)
... additional stack trace through to dpd, bluebird etc.

Cannot replicate through isolation

Go ahead and try setting up a scrap project: yarn add handlebars handlebars-helper-ternary handlebars-helpers handlebars.numeral

Then run this script in nodejs:

const   handlebars = require('handlebars'),
        numeralHelper = require('handlebars.numeral'),    
        ternaryHelper = require('handlebars-helper-ternary'),
        helpers = require('handlebars-helpers')({
        handlebars: handlebars
    });
console.log(`Testing...`);
const base = `
<html>
    <body style="font-family:'Segoe UI', Tahoma, Geneva, Verdana,     'sans-serif'; font-size: larger;">
    {{>@partial-block }}
    <td style="text-align: center; padding: 24px;">
    Copyright 2018 My Company, Inc. All rights reserved.

    </body>
</html>

`;
const inner = `
{{#>base}}
    {{subscriber.name}},

    {{member.name}} has received a notifier from {{subscriber.name}}.    

    Click the link below to review!. 
    <a href='{{link}}'>Go!</a>

    Thank you,
    My Company
{{/base}}
`;
numeralHelper.registerHelpers(handlebars);
handlebars.registerHelper('ternary', ternaryHelper);
handlebars.registerHelper("moduloIf", function (index_count, mod, block)     {

    if (index_count > 0 && parseInt(index_count) % (mod) === 0) {
        return block.fn(this);
    } else {
        return block.inverse(this);
    }
});

handlebars.registerHelper("substitute", function(a, options) {
  try {
    function index(obj,i) { return obj ? obj[i] : {} }
    let data = a.split('.').reduce(index, this);
    if (data && typeof data === 'string') return data;
    else return options.fn(this);
  } catch (e) {
    console.log('substitute helper:' + e);
  }
});
handlebars.registerPartial('base',base)
var output = handlebarspile(inner)({name:'Gus'});
console.log('Output:');
console.log(output)

Further consideration

In actuality we have the handlebars require wrapped in another module with code run against the handlebars instance as illustrated in the sample script. We're exporting the handlebars instance.

Premise

We've got handlebars running in a backend nodejs application for templating various messages that get sent.

Handlebars.pile throws this exception (when piling templates from partials)

Error: You must pass a string or Handlebars AST to Handlebars.pile. You passed <html>
<head>
... extremely long markup
at Object.pile (/Users/guscrawford/rollick-management-console/deployd/node_modules/handlebars/dist/cjs/handlebars/piler/piler.js:501:11)
at HandlebarsEnvironment.hb.pile (/Users/guscrawford/rollick-management-console/deployd/node_modules/handlebars/dist/cjs/handlebars.js:39:40)
at Object.invokePartialWrapper [as invokePartial] (/Users/guscrawford/rollick-management-console/deployd/node_modules/handlebars/dist/cjs/handlebars/runtime.js:71:44)
... additional stack trace through to dpd, bluebird etc.

Cannot replicate through isolation

Go ahead and try setting up a scrap project: yarn add handlebars handlebars-helper-ternary handlebars-helpers handlebars.numeral

Then run this script in nodejs:

const   handlebars = require('handlebars'),
        numeralHelper = require('handlebars.numeral'),    
        ternaryHelper = require('handlebars-helper-ternary'),
        helpers = require('handlebars-helpers')({
        handlebars: handlebars
    });
console.log(`Testing...`);
const base = `
<html>
    <body style="font-family:'Segoe UI', Tahoma, Geneva, Verdana,     'sans-serif'; font-size: larger;">
    {{>@partial-block }}
    <td style="text-align: center; padding: 24px;">
    Copyright 2018 My Company, Inc. All rights reserved.

    </body>
</html>

`;
const inner = `
{{#>base}}
    {{subscriber.name}},

    {{member.name}} has received a notifier from {{subscriber.name}}.    

    Click the link below to review!. 
    <a href='{{link}}'>Go!</a>

    Thank you,
    My Company
{{/base}}
`;
numeralHelper.registerHelpers(handlebars);
handlebars.registerHelper('ternary', ternaryHelper);
handlebars.registerHelper("moduloIf", function (index_count, mod, block)     {

    if (index_count > 0 && parseInt(index_count) % (mod) === 0) {
        return block.fn(this);
    } else {
        return block.inverse(this);
    }
});

handlebars.registerHelper("substitute", function(a, options) {
  try {
    function index(obj,i) { return obj ? obj[i] : {} }
    let data = a.split('.').reduce(index, this);
    if (data && typeof data === 'string') return data;
    else return options.fn(this);
  } catch (e) {
    console.log('substitute helper:' + e);
  }
});
handlebars.registerPartial('base',base)
var output = handlebars.pile(inner)({name:'Gus'});
console.log('Output:');
console.log(output)

Further consideration

In actuality we have the handlebars require wrapped in another module with code run against the handlebars instance as illustrated in the sample script. We're exporting the handlebars instance.

Share Improve this question edited Jun 4, 2018 at 13:10 Gus Crawford asked Jun 4, 2018 at 12:33 Gus CrawfordGus Crawford 1,0378 silver badges18 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 13

The string was a Buffer

Despite logging typeof the template string I was passing as a string, the output of readFileAsync without passing an encoding is a raw node Buffer.

Duh

The error is clear, you're passing something that isn't a string or AST.

This is the only way handlebars throws that error.

if (input == null || (typeof input !== 'string' && input.type !== 'Program')) {
    throw new Exception('You must pass a string or Handlebars AST to Handlebars.pile. You passed ' + input);
}

You're probably passing an object, with a toString method, that's why you see:

You passed <html>
<head>
... extremely long markup

const input = {
  toString() {
    return `<html>
    <head>`;
  }
}
console.log('You must pass a string or Handlebars AST to Handlebars.pile. You passed ' + input);

This solved it for me:

const template:Handlebars.TemplateDelegate | null = Handlebars.pile(new XMLSerializer().serializeToString(your html document or string));

console.log(template({your_key : "your_value"})) 

It probably converts a document type to an XML string representing a DOM tree.
Javascript is a bit hard to deal with.

本文标签: