Jan 24, 2020 6 min read
You won’t miss console.log, I promise.
Senior Application Developer
Chrome comes with a built-in tool called “sources” available in the developer console, accessible by going to View > Developer > Developer Tools in the menu, or by pressing
Quick disclaimer: I am actually using Brave (https://brave.com), which is almost identical to chrome except for some additional privacy add-ons.
Already you probably see some folders and files available in the “Page” tab of the Sources tab. These in themselves are moderately useful — if for example you only have access to the live site and not the source code — and in some cases, without a source map you might be forced to use them. But the real power of this tool is realized through the use of source mapping.
resources/js. As you can see on the right of the image, the dev tools have notified me a source map was detected — we’re looking good so far!
Now that you’ve got your source code loaded into Chrome’s developer tools, let’s start doing some basic debugging!
Within the sources tab navigate to the file where you want to set a breakpoint, then in the left margin of the editor click and you should see a green arrow appear. This is the most basic breakpoint, it will be executed (it will freeze the state, more specifically) when your program executes that line.
From here you are able to inspect things by setting watchers or viewing variables that are within the scope of the line you set the breakpoint on. Personally I tend to roll with watchers because then I can specify only what I want to see and I can narrow down large objects to smaller atomic bits of data that I find more helpful. In the right panel of the developer tools, you should see eight accordion tabs, illustrated in the image below.
To set a watcher, click the plus icon in the “Watch” tab and type out the variable you want to view relative to the scope of your breakpoint; typically in a Vue.js app that will probably be
this and some additional path information, but it could also be any local variables as well.
Setting breakpoints in this fashion is particularly powerful because you don’t have to go and throw
console.log's everywhere and recompile/dirty up your code in order to see how the state is mutating. It’s particularly helpful when a simple behavior might generate 10’s or 100’s of lines of logged values — causing you to have to essentially sift through the state as a block of dead text. Using a breakpoint you can even manipulate values in your watch window in real-time, exploring how a behavior might change with different inputs before you even have to touch the code.
Next, my personal favorite: conditional breakpoints. Setting conditional breakpoints is extremely helpful (and satisfying) when working with a section of code that may get called hundreds or thousands of times (like a loop or function) and you don’t want to manually step through it until you hit the portion of data you want to observe being processed. With conditional breakpoints, you can say essentially “break when x condition becomes true” — such as when the key in loop is “user” or a value contains something you’re looking for. To add a conditional breakpoint, add a normal breakpoint first, then right-click on it and go to “edit breakpoint.”
In the image above I’ve specified that I want the breakpoint to become active only when
x === 25. Let’s give it a shot and see if it works. Locally defined variables actually display their values inline as you can see,
x is 25 at this iteration of the loop when the breakpoint kicked in.
Last but not least, the feature I want to specifically point out is the “Call Stack” tab in the right panel. This can be a particularly useful tool when you’re perhaps trying to trace the origin of a request, i.e. is this method being called from where I think it is? Maybe an event you think is being called from one place is being called from another place as well; rather than add a trail of
console.log statements you can stick a breakpoint at the line in question and see if it’s being called multiple times and what’s calling it. The stack traces can be quite large, but they run in order of the last (most nested) call on top, and the origination point at the bottom of the stack. I tend to need what’s at the top or at the very bottom, and the in-between is typically filled with a lot of innocuous stuff that I don’t care about. Not always the case, but generally speaking it seems to be for me.
There is so much more to be said about this tool but I feel with these basics you’ll be able to delve deeper into the specific tools and how they best serve your development needs.
Thanks for reading, feel free to leave comments or questions!