Skip to content
This repository

_.template syntax errors too hard to debug #666

Closed
ianb opened this Issue July 10, 2012 · 20 comments

4 participants

Ian Bicking Jeremy Ashkenas brad dunbar John-David Dalton
Ian Bicking
ianb commented July 10, 2012

If you have a syntax error in your generated template, you just get an exception from var render = new Function(settings.variable || 'obj', '_', source); – not very helpful, and you can't view the source of the template.

I'm not quite sure what to do, though try/catch around that might help. The exception itself will always be kind of bad. So maybe:

try {
  var render = ...
} catch (e) {
  e.generatedSource = e;
  throw e;
}

And that would have to be documented, I guess, otherwise you'd never notice that. And I'm not sure if all errors can have attributes added to them. But... something would be helpful.

brad dunbar
Collaborator

Hi @ianb! You're right, syntax errors from new Function(...) are hard to debug since you don't get a line number. However, two things have been done recently to help with this (in the latest version of underscore).

  1. Source Lines - Template source lines are now separated instead of munged into one. At the very least, this makes it much easier to debug the error from the console.
  2. Precompilation - Since it's now possible to precompile templates via _.template(...).source, you can precompile your templates server-side and send them to the browser as plain javascript. This means you'll get line numbers with the syntax error. Even if you can't precompile them server-side you can still debug the syntax error with a quick node script to compile the template.

Hope these help!

Ian Bicking
ianb commented July 11, 2012

Note that syntax errors are a little different than runtime errors. I should have given an example: _.template('<% if x %>')

There's no successful template object created because just constructing the Function object fails.

lodash tried to address this in this commit: lodash/lodash@10886be

brad dunbar
Collaborator

Ah. Yes, of course, though the first point still stands. :)

lodash tried to address this in this commit: lodash/lodash@10886be

Why is it helpful to defer throwing the error? It seems to me this would lead to silent template compilation failures.

Ian Bicking
ianb commented July 11, 2012

lodash's change is not the one I'd have thought of, though in the particular case I encountered it would have been helpful. In cases where you aren't aggressively precompiling templates I think lodash's approach is sensible – deferring the error for a couple lines of code doesn't make it harder to debug. Annotating or rewriting the exception object is more what I'd expect.

Also as it currently stands the first point would be helpful if I could get my hands on the syntactically invalid generated code, but right now I can't.

John-David Dalton

@braddunbar

Why is it helpful to defer throwing the error?

This way the template and its source are debuggable. Normally, for non-syntax error related failures compiled templates that error when passed a data object, either through _.template(string, data) or deferred via _.template(string), have sourceURLs associated with them so devs can simply look them up in their console to see the compiled source.

It seems to me this would lead to silent template compilation failures.

Because errors are deferred until execution rather than creation it allows it to be debugged in the same way you suggested.

brad dunbar
Collaborator

This way the template and its source are debuggable.

You mean that you can still do console.log(_.template('...').source) when the template has a syntax error?

John-David Dalton

@braddunbar

You mean that you can still do console.log(_.template('...').source) when the template has a syntax error?

Yap.

brad dunbar
Collaborator

I see how that's handy, but it poses a problem when precompiling templates. The code below would spit out code with a syntax error without warning, which I think is undesirable.

// Logs code with a syntax error.
console.log(_.template('<% syntax error %>').source);
John-David Dalton

I see how that's handy, but it poses a problem when precompiling templates. The code below would spit out code with a syntax error without warning, which I think is undesirable.

They would be debugging it because it threw an error in the first place. The warning bells will have already been sounded.

brad dunbar
Collaborator

I meant precompiling server-side before delivering to the browser, where the template would not be executed.

John-David Dalton

I meant precompiling server-side before delivering to the browser, where the template would not be executed.

If they precompile and use the .source to inline it for delivery then it will error on client. Then they will go debugging the template they just inlined on the server-side and will be able to.

I make heavy use of compiled and inlined templates during the runtime and build process of Lo-Dash. If I or any other dev runs into issues or annoyances with the safeguard I'll simply tweak it. I'm going to stick it out for now.

Ian Bicking
ianb commented July 11, 2012

This is roughly what I'd propose: https://github.com/ianb/underscore/tree/add-source-to-template-exceptions

Documentation here would be important (but I'm not clear where that is), as no one will notice this exception.source attribute on their own.

brad dunbar
Collaborator

@jdalton Ok, thanks for the info!

@ianb What situation causes errors when assigning e.source = source?

Ian Bicking
ianb commented July 11, 2012

The try/catch around e.source = source is defensive programming – there's nothing I hate more than an exception in my exception handler, and I'm not sure how writable all possible exceptions may be.

Jeremy Ashkenas jashkenas closed this in 4e6b147 August 31, 2012
Jeremy Ashkenas
Owner

Instead of attaching the garbled source, I've gone ahead and added the original body of the template to the error.

Ian Bicking
ianb commented August 31, 2012

But I already have the original body, it's the argument I passed in. It's the generated source I have no access to. This change doesn't add any new information.

Jeremy Ashkenas
Owner

Ah, then I misunderstand the original problem. I thought you were having trouble figuring out which template was causing the syntax error. How does the generated source help you debug a template syntaxerror exactly?

Jeremy Ashkenas jashkenas referenced this issue from a commit August 31, 2012
Jeremy Ashkenas Revert "adding a test for #666"
This reverts commit b24a1c2.
fd801af
Jeremy Ashkenas jashkenas referenced this issue from a commit August 31, 2012
Jeremy Ashkenas Revert "Fixes #666: Adds a 'template' property to the error, whenever…
… you have a SyntaxError in a _.template"

This reverts commit 4e6b147.
be778eb
Ian Bicking
ianb commented August 31, 2012

In part it's just another thing to stare at to try to figure out what's syntactically wrong. But I can also drop the generated source into an editor and get syntax feedback there, and I can see what the line numbers map to. As it stands, when I've gotten syntax errors in my templates the only approach I've found to fixing them is to look really hard at the complete template and try to see what I got wrong.

Jeremy Ashkenas
Owner

Alright -- I'm not sure if we should document it, because it seems like a really pessimal debugging technique ... but I also don't see the harm, and I can imagine it being useful when dealing with somebody else's template on deadline ;)

Ian Bicking
ianb commented August 31, 2012

I only opened the bug because it happened to me, so there is at least anecdotal evidence of this being useful ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.