Debugging notes

Table of contents

You can find here some notes I wrote while watching an excellent talk by Rebecca Hill: Essential JavaScript debugging tools for the modern detective

$ (dollar) selector

The tips in this section are for the console tab of Chrome DevTools.

  • $ is an alias for document.querySelector:

    // the following statements are equivalent:
    $("#an-id");
    document.querySelector("#an-id");
  • $$ is an alias for document.querySelectorAll:

    // the following statements are equivalent:
    $$("p");
    document.querySelectorAll("p");
  • $0 returns the most recent HTML element you inspected; $1 the second most recent and so forth until $4. Console Utilities API Reference: \$0-\$4

Logging stuff to the console

  • Prefer console.log({ variable })—wrap the variable inside an object—instead of console.log(variable) to get a little more context:

    var number = 1;
    console.log(number); // prints: 1
    console.log({ number }); // prints { number: 1 }
  • console.table makes more readable the logs for your arrays of objects:

    const users = [
      { name: "John", age: 26 },
      { name: "Jane", age: 39 },
    ];
    console.table(users);

    The code above prints:

    Results from console.table
    Results from console.table
  • console.group creates collapsable groups of console logs:

    console.group("Greetings");
    console.log("Hello");
    console.log("World");
    console.groupEnd();

    The statements above prints:

    Results from console.group/groupEnd
    Results from console.group/groupEnd
  • Use console.trace to quick log the call stack.

  • Use console.dir if you want to inspect an HTML element as an object instead of logging its markup with console.log. Consider the following examples:

    console.log() prints:

    Results from console.log
    Results from console.log

    console.dir prints:

    Results from console.dir
    Results from console.dir
  • console.dir is even more useful in Node because it adds colors, and you can inspect nested objects instead of only logging something like: [Object]. Consider the following example:

    const user = {
      name: "John",
      age: 26,
      pets: [
        { name: "Azor", type: "dog", favouriteOwner: { name: "Sally" } },
        { name: "Kitty", type: "cat" },
      ],
    };
    console.log(user); // prints:
    // {
    //   name: 'John',
    //   age: 26,
    //   pets: [
    //     { name: 'Azor', type: 'dog', favouriteOwner: [Object] },
    //     { name: 'Kitty', type: 'cat' } ]
    // }
    const options = { colors: true, depth: null };
    console.dir(value, options); // prints:
    // {
    //   name: 'John',
    //   age: 26,
    //   pets: [
    //     { name: 'Azor', type: 'dog', favouriteOwner: { name: "Sally" } },
    //     { name: 'Kitty', type: 'cat' } ]
    // }

To make your life easier, find or create VS Code snippets for logging stuff into console. ES7 snippets extension for VS Code has some console snippets:

PrefixMethod
clg→console.log(object)
clo→console.log("object", object)
ctm→console.time("timeId")
cte→console.timeEnd("timeId")
cas→console.assert(expression,object)
ccl→console.clear()
cco→console.count(label)
cdi→console.dir
cer→console.error(object)
cgr→console.group(label)
cge→console.groupEnd()
ctr→console.trace(object)
cwa→console.warn
cin→console.info

Debugging

You can debug your JavaScript applications with VS Code’s Debugger for Chrome extension.

CRA debug:

For CRA app you need the following .vscode/launch.json config:

.vscode/launch.json
{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "name": "CRA Debug",
      "url": "http://localhost:3000",
      "webRoot": "${workspaceFolder}/src",
      "sourceMapPathOverrides": {
        "webpack:///src/*": "${webRoot}/*"
      }
    }
  ]
}

You don’t have to specify the sourceMapPathOverrides explicitly because the default value includes what we specify in the above code snippet.

Gatsby debug

If you want to debug Gatsby’s development build, you need a similar launch.json config, but you’ll have to change the port from 3000 to 8000.

You also have to override the Webpack configuration (at the time of writing at least) in develop stage to include the eval-source-map devtool. Otherwise, the line numbering will be messed up, and you won’t be able to add breakpoints. Relevant GitHub issue

gatsby-node.js
exports.onCreateWebpackConfig = ({ stage, actions }) => {
  if (stage === "develop") {
    actions.setWebpackConfig({
      devtool: "eval-source-map",
    });
  }
};
  • You can add breakpoints to DOM nodes by right-clicking and selecting “break on” under the Elements tab inside DevTools. For example, you can add breakpoints to monitor an attribute change or when the DOM node gets removed.
  • You can add conditional breakpoints (based on a known variable): @ 11:47 in the video.
  • The “pause on all/uncaught exceptions” can be useful.
  • Use “Blackbox script” to stop stepping into certain scripts. For example, black box an external library script because the bug you’re investigating is more likely to be inside your codebase, not in the external library. You can enable that by right-clicking in a file under the Sources tab and selecting “Blackbox script”.

DevTools snippets @ 14:20

Other things to read

Popular

Previous/Next