最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Handlebars.compile throws an exception 'Error: You must pass a string or Handlebars AST to Handlebars.compi

programmeradmin1浏览0评论

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.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论