vue icon indicating copy to clipboard operation
vue copied to clipboard

Add line number and a snippet of the source template to template render error reports

Open davidkhess opened this issue 4 years ago • 6 comments

What problem does this feature solve?

It helps developers pinpoint template errors in larger templates.

At the moment, render errors look like this (from version 2.5.18):

vue.js:616 [Vue warn]: Error in render: "TypeError: Cannot read property 'name' of undefined"

found in

---> <ASelectDate>
       <ALite>
         <TransitionGroup>
           <DbNavigation>
             <VContent>
               <VApp>
                 <Root>
warn @ vue.js:616
logError @ vue.js:1824
globalHandleError @ vue.js:1819
handleError @ vue.js:1808
Vue._render @ vue.js:4637
updateComponent @ vue.js:2893
get @ vue.js:3261
Watcher @ vue.js:3250
mountComponent @ vue.js:2900
Vue.$mount @ vue.js:8642
Vue.$mount @ vue.js:11045
init @ vue.js:4225
createComponent @ vue.js:5696
createElm @ vue.js:5643
addVnodes @ vue.js:5824
updateChildren @ vue.js:5951
patchVnode @ vue.js:6037
patch @ vue.js:6198
Vue._update @ vue.js:2775
updateComponent @ vue.js:2893
get @ vue.js:3261
run @ vue.js:3336
flushSchedulerQueue @ vue.js:3094
(anonymous) @ vue.js:1925
flushCallbacks @ vue.js:1844
Promise.then (async)
microTimerFunc @ vue.js:1892
nextTick @ vue.js:1938
queueWatcher @ vue.js:3186
update @ vue.js:3326
notify @ vue.js:727
mutator @ vue.js:879
goto_date @ lite.js:82
invoker @ vue.js:2128
Vue.$emit @ vue.js:2646
Vue.<computed> @ backend.js:1793
success @ select_year_trim.js:296
tryCatcher @ -internal.js:39
invokeCallback @ -internal.js:211
publish @ -internal.js:197
flush @ asap.js:80
characterData (async)
(anonymous) @ asap.js:54
asap @ asap.js:11
fulfill @ -internal.js:148
handleMaybeThenable @ -internal.js:113
resolve @ -internal.js:121
(anonymous) @ -internal.js:241
(anonymous) @ util.js:37
Request.callback @ superagent.js:1723
(anonymous) @ superagent.js:1550
Emitter.emit @ superagent.js:1080
xhr.onreadystatechange @ superagent.js:1817
XMLHttpRequest.send (async)
Request._end @ superagent.js:1884
Request.end @ superagent.js:1788
(anonymous) @ util.js:34
initializePromise @ -internal.js:236
Promise @ promise.js:142
superagent.Request.promise @ util.js:33
common_setup @ managers.js:33
self.get_availability @ managers.js:163
select_car @ select_year_trim.js:272
select @ VM2579:1
invoker @ vue.js:2128
Vue.$emit @ vue.js:2646
Vue.<computed> @ backend.js:1793
click @ VM2609:3
invoker @ vue.js:2128
Vue.$emit @ vue.js:2646
Vue.<computed> @ backend.js:1793
click @ VBtn.ts:114
invoker @ vue.js:2128
fn._withTask.fn._withTask @ vue.js:1913

vue.js:1828 TypeError: Cannot read property 'name' of undefined
    at Proxy.eval (eval at createFunction (vue.js:10785), <anonymous>:2:39)
    at VueComponent.Vue._render (vue.js:4635)
    at VueComponent.updateComponent (vue.js:2893)
    at Watcher.get (vue.js:3261)
    at new Watcher (vue.js:3250)
    at mountComponent (vue.js:2900)
    at VueComponent.Vue.$mount (vue.js:8642)
    at VueComponent.Vue.$mount (vue.js:11045)
    at init (vue.js:4225)
    at createComponent (vue.js:5696)

While TypeError: Cannot read property 'name' of undefined and the template it occurred in is of course quite useful information it could be better if there are many references to 'name' in <ASelectDate> and the exact location of the error is not obvious. I'm proposing a feature enhancement that would include a line number relative to the template itself (assuming it is not just a render function) and also output the line before, the line of the error and the line following it from the source template to provide context information to the developer.

I believe this can be achieved using the same techniques that are used in compilers when debugging information is enabled and generated. In development mode, as a template is compiled, context information is maintained (line numbers and the source lines of the template) and as each piece is compiled and converted into render function code this information is captured as "debugging symbols" (using compiler terms). If this debugging information is available when a render error occurs, the stack trace is examined and used with the debugging information to determine the line number and template lines to display with the warning.

The result would be an error report that looks something like:

vue.js:616 [Vue warn]: Error in render: "TypeError: Cannot read property 'name' of undefined"

found in

---> <ASelectDate>
       <ALite>
         <TransitionGroup>
           <DbNavigation>
             <VContent>
               <VApp>
                 <Root>

on line 34

        <p class="model-year">{{ model.year }}</p>
--->    <p class="model-name">{{ model.name }}</p>
        <p class="model-tagline">{{ model.tag_line }}</p>

What does the proposed API look like?

In terms of implementation details, this feature would be enabled in development mode. The debugging information would be generated during template compilation and could be attached to the render function itself when compiled and emitted so that no additional files need to be produced, packaged or loaded. If the debugging information is available, the error message as envisioned above is produced. If not, the current style of warning is emitted instead along with a message that says for better details, reproduce the error in development mode.

davidkhess avatar Dec 30 '19 14:12 davidkhess

I don't think this will be technically possible for current Vue 2 but the source maps in Vue 3 does already allow breaking in the middle of the template so I think it might be possible to have this. @znck do you happen to know more?

posva avatar Dec 30 '19 16:12 posva

You can write a custom directive but let me try it and confirm.

znck avatar Dec 30 '19 16:12 znck

I wasn't aware of the source map support in Vue 3 - that's some good news!

Looks like this might be useful in that scenario:

https://www.stacktracejs.com/#!/docs/stacktrace-gps

It appears to load and parse a source map and convert a stack trace frame to a location in the context of the source map.

It also has an MIT license and isn't a lot of code so it could be readily adapted and integrated.

davidkhess avatar Dec 30 '19 21:12 davidkhess

I vote for this proposal as well

literakl avatar Apr 03 '20 19:04 literakl

This is a great idea, I don't know how people debug templates with hundreds of lines today.

pedro380085 avatar Jul 07 '20 03:07 pedro380085

@posva has there been any action on this in Vue 3? If not, I may have the cycles to put together a PR for it.

davidkhess avatar May 03 '22 01:05 davidkhess