Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

_.template syntax errors too hard to debug #666

Closed
ianb opened this Issue · 20 comments

4 participants

@ianb

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.

@braddunbar
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!

@ianb

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

@braddunbar
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.

@ianb

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.

@jdalton
Collaborator

@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.

@braddunbar
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?

@jdalton
Collaborator

@braddunbar

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

Yap.

@braddunbar
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);
@jdalton
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.

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

@braddunbar
Collaborator

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

@jdalton
Collaborator

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.

@ianb

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.

@braddunbar
Collaborator

@jdalton Ok, thanks for the info!

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

@ianb

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.

@jashkenas jashkenas closed this in 4e6b147
@jashkenas
Owner

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

@jashkenas jashkenas referenced this issue from a commit
@jashkenas adding a test for #666 b24a1c2
@ianb

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.

@jashkenas
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?

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

This reverts commit 4e6b147.
be778eb
@ianb

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.

@jashkenas
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 ;)

@ianb

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.