Modern frameworks like Vue.js do a ton for you. They manage DOM updates, maintain component lifecycles, and more.

Layer on higher level frameworks like Nuxt.js and even more is taken care of you. The plugin system lets you mix in behavior into all of your components automatically. Layouts, pages, and components are all seamlessly interwoven behind the scenes.

But one of the key questions is - what happens when things break down? When something goes wrong, and there is so much happening behind the scenes outside of your code, how do you debug it?

How do you follow the complex interweaving of runtime code, framework code, third party plugins, and your own code? It's almost like unraveling a murder mystery. So much so, that I decided that the right way to talk about it might be to tell it as an unraveling mystery.

So here we go. Follow me as we walk through debugging a recent tricky bug I ran into, tracing the "culprit" down and along the way learning what types of forensic tooling we have at our disposal.

The setup

The bug occurred for me in a client application where I was using the vue-select component.

I updated the version of the vue-select package from v2.4.0 to v2.5.0 in order to get a new feature, but upon testing I found that the package was no longer working right.

In particular, this plugin allows you to type into an input, and it will automatically filter down the list of available options. After upgrading, that filtering wasn't working.

My first assumption was that something in the way I was using the component was no longer supported. I looked at the documentation, and it looked like everything I was doing was right... in fact there was an example almost identical to the way I was using it.

I pulled down the package repository and put my example into it - it worked fine there. So clearly something weird was going on. Time to really dig into debugging.

Starting place - the console

My first stop was to open up the browser console and see if there was a javascript error. Maybe something else in my application was breaking, and the component was not getting fully set up.

While I didn't find an error, I did see an odd pair of warnings:

Vue Warn Messages

'Method "filterBy" has already been defined as a prop' - that seemed like a hint. Maybe I was defining filterBy somewhere I shouldn't? But searching through my code turned up nothing at all.

Looking into the vue-select source code was no more illuminating. I could see filterBy being defined as a prop, but no redefinition anywhere that might lead to this warning.

If there had been an actual error, I could have looked at the backtrace, but the warnings were coming from deep inside Vue internals.

Inspecting the component

To try to figure out what was going on, I used the Vue devtools to get a look at the component during runtime.

I knew that by default, the filterBy prop for vue-select should get set to a function that looked like:

function(option, label, search) {
  return (label || '').toLowerCase().indexOf(search.toLowerCase()) > -1
}

I selected the component in the Vue devtools and used the fact that it created a reference to the component named $vm0 to log out the function:

Log of filterBy function

Not a match at all! There was in fact a new function coming in... but when I searched through my codebase for the function signature filterBy (arr, search), or even just the arguments, nothing turned up.

And I still didn't have any indication as to what was setting that new function, and when... only that something was in fact setting a new function.

Had I been a little smarter just then, I could have found it, but I didn't. We'll come back to what I could have done better, but first, the breakthrough that led to the solution:

Never miss a new post!

Get our latest post in your inbox every Tuesday by subscribing to the Vue.js Developers Newsletter.

With more than 7000 subscribers, the newsletter will deepen your knowledge of Vue with weekly must-read articles.

This subscription also includes Vue.js Developers promotional emails. You can opt-out at any time. View our privacy policy.

The Breakthrough: Inserting a Breakpoint within warn

The breakthrough came when I realized that even though the warning was not happening in code that I could point to, it might have context that I could use to trace things down.

I clicked through to the warning code in the chrome DevTools and inserted a breakpoint.

Inserting Breakpoint

Reloading with this in place would let me then examine the state of the Vue vm at the time the warning was triggered.

Doing so, I saw nothing immediately obvious... the vm had filterBy defined, but it looked like the expected function.

So I started stepping forward in the debugger, and it popped me up to the function that had triggered the warning:

initMethods function

Ah-hah! Now we can directly inspect the method that is triggering the warning: it's in the methods object:

methods object

The key is the link to source location. It was in the vendors.app.js bundle... if I had properly set up sourcemapping in the project to include node modules it would have pointed me straight to the source, but even without that I could click through and scroll up to see the webpack annotation to show me the source:

The Smoking Gun

The function was coming from vue2-filters, another 3rd party plugin that I had installed without worrying too much about it. This plugin installs a set of common filters, including some that are implemented as methods. One of those methods just happened to be named filterBy, and was clobbering the prop in vue-select.

Voila! The solution!

The shortcut that could have been

I mentioned earlier that if I'd been a little smarter, I could have found the issue when I first logged the filterBy function and saw it was different.

It turns out, had I inspected the $vm0 object that was my VSelect component, rather than just logging out the filterBy function, devtools would have actually let me click through to the source code at that point.

The Missed Reference

So I could have arrived at the solution one step faster. Interestingly, in the Firefox version of the devtools this reference does not appear to be there, but the warn approach still functions.

More Information and Resources

I hope you've enjoyed this "detective story" and gotten some ideas that will help you debug your Vue.js applications.

If you want to explore this debugging problem yourself, I've set up a barebones application with Nuxt 2.0 that reproduces the issue in github here.

All of these debugging examples were done with Chrome devtools plus the Vue Devtools Chrome extension. A similar extension exists for Firefox and also as an Electron app that will work in any environment.

You may also be interested in these additional resources:


Kevin Ball

About Kevin Ball

Kevin Ball is the president of ZenDev, LLC, where he helps developers and teams level up their front-end skills. He just launched LearnVueJS.com, a project dedicated to teaching developers about Vue.js, and is offering a set of free webinars on the fundamentals of Vue.