{"id":1616,"date":"2024-04-08T17:10:27","date_gmt":"2024-04-08T23:10:27","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=1616"},"modified":"2024-04-08T17:10:28","modified_gmt":"2024-04-08T23:10:28","slug":"node-js-debugging-in-chrome-devtools","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/node-js-debugging-in-chrome-devtools\/","title":{"rendered":"Node.js Debugging in Chrome DevTools"},"content":{"rendered":"\n<p>I was pairing with my co-worker last week. They had a super different debugging style than I do. I&#8217;m <em>aware<\/em> that I can do fancy things in DevTools, like set breakpoints and whatnot right from within DevTools and use well-placed <code>debugger;<\/code> statements to halt JavaScript execution and inspect things at that point. <\/p>\n\n\n\n<p>But I hardly ever do any of that. <\/p>\n\n\n\n<p>I&#8217;m quite sure I don&#8217;t even <em>know<\/em> all the cool tricks. I&#8217;m a <code>console.log()<\/code> type. I just absolutely litter the code in them until I learn what I need to learn. It&#8217;s a little amateur-ish, I admit. I&#8217;ve made it this far, but there&#8217;s no time like now to level up. <\/p>\n\n\n\n<p>I <em>especially<\/em> don&#8217;t know any tricks with Node.js debugging. To begin with, I didn&#8217;t even know you could use Chrome DevTools with Node.js. It sort of makes sense since Node.js <a href=\"https:\/\/nodejs.org\/en\/learn\/getting-started\/the-v8-javascript-engine\">uses v8<\/a> just like Chrome does, but it never clicked with me to use a browser tool for server code. It&#8217;s not a new thing! Paul Irish was <a href=\"https:\/\/medium.com\/@paul_irish\/debugging-node-js-nightlies-with-chrome-devtools-7c4a1b95ae27\">telling people how to do this<\/a> in 2016. <\/p>\n\n\n\n<p>The kind of debugging my co-worker and I were doing was complex enough that having DevTools to help us really worked. I think I&#8217;m a believer. For this article though, I&#8217;m going to show you how to do it with a simple example. You probably wouldn&#8217;t need DevTools for this, but the point is learning how to do it. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1) Have Chrome Open<\/h2>\n\n\n\n<p>Then go to <code>chrome:\/\/inspect\/<\/code>. The first tab, Devices, has the link you&#8217;re looking for. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"637\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.34.11%402x.png?resize=1024%2C637&#038;ssl=1\" alt=\"\" class=\"wp-image-1625\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.34.11%402x.png?resize=1024%2C637&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.34.11%402x.png?resize=300%2C187&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.34.11%402x.png?resize=768%2C478&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.34.11%402x.png?resize=1536%2C956&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.34.11%402x.png?resize=2048%2C1275&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"733\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.38.56%E2%80%AFPM.png?resize=1024%2C733&#038;ssl=1\" alt=\"\" class=\"wp-image-1626\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.38.56%E2%80%AFPM.png?resize=1024%2C733&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.38.56%E2%80%AFPM.png?resize=300%2C215&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.38.56%E2%80%AFPM.png?resize=768%2C550&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.38.56%E2%80%AFPM.png?resize=1536%2C1100&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.38.56%E2%80%AFPM.png?resize=2048%2C1466&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>These settings work for me, but if you run Node at some specific port or local URL, you should add it here. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2) Have Node Code<\/h2>\n\n\n\n<p>Kinda goes without saying, but you&#8217;re going to need to execute some Node code, likely from your terminal, in order for there to be anything to expect. Might be an npm script or something. Let&#8217;s just assume we have a file called <code>app.js<\/code> and we&#8217;re going to run it directly like <code>node app.js<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"748\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.41.02%402x.png?resize=1024%2C748&#038;ssl=1\" alt=\"\" class=\"wp-image-1627\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.41.02%402x.png?resize=1024%2C748&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.41.02%402x.png?resize=300%2C219&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.41.02%402x.png?resize=768%2C561&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.41.02%402x.png?resize=1536%2C1121&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.41.02%402x.png?resize=2048%2C1495&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">3) Have a Problem<\/h2>\n\n\n\n<p>My goal with this code was to have&#8230;<\/p>\n\n\n\n<p><code>Hello World<\/code><\/p>\n\n\n\n<p>&#8230; turn into: <\/p>\n\n\n\n<p><code>Hello \ud83d\udc4b World!!!<\/code><\/p>\n\n\n\n<p>That is, put a wave emoji between each word. But the output I was getting was:<\/p>\n\n\n\n<p><code>undefinedHello \ud83d\udc4f World \ud83d\udc4f !!!<\/code>.<\/p>\n\n\n\n<p>That&#8217;s a problem because:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>I don&#8217;t want <code>undefined<\/code> there<\/li>\n\n\n\n<li>It put a wave at the end too<\/li>\n\n\n\n<li>There is a space before the &#8220;!!!&#8221;.<\/li>\n<\/ol>\n\n\n\n<p>We must fix this super contrived example!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4) Execute the Node Code with an Inspection Flag<\/h2>\n\n\n\n<p>Like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">node --inspect-brk app.js<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>That <code>--inspect-brk<\/code> flag is the real magic here. <\/p>\n\n\n\n<p>When I do that, the terminal output will tell me where Node is running and that the Debugger is attached:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"157\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.45.36%E2%80%AFPM.png?resize=1024%2C157&#038;ssl=1\" alt=\"\" class=\"wp-image-1628\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.45.36%E2%80%AFPM.png?resize=1024%2C157&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.45.36%E2%80%AFPM.png?resize=300%2C46&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.45.36%E2%80%AFPM.png?resize=768%2C118&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.45.36%E2%80%AFPM.png?w=1496&amp;ssl=1 1496w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>It will automatically pause before it starts executing.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"516\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.46.09%E2%80%AFPM.png?resize=1024%2C516&#038;ssl=1\" alt=\"\" class=\"wp-image-1629\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.46.09%E2%80%AFPM.png?resize=1024%2C516&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.46.09%E2%80%AFPM.png?resize=300%2C151&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.46.09%E2%80%AFPM.png?resize=768%2C387&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.46.09%E2%80%AFPM.png?resize=1536%2C775&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/Screenshot-2024-04-08-at-3.46.09%E2%80%AFPM.png?resize=2048%2C1033&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">5) Go through the Code<\/h2>\n\n\n\n<p>These buttons are of particular interest:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"764\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.47.16%402x.png?resize=1024%2C764&#038;ssl=1\" alt=\"\" class=\"wp-image-1630\" style=\"width:537px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.47.16%402x.png?resize=1024%2C764&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.47.16%402x.png?resize=300%2C224&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.47.16%402x.png?resize=768%2C573&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.47.16%402x.png?w=1032&amp;ssl=1 1032w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>If you press &#8220;Play&#8221; here (that first blue one), the code will just run and be done without much a chance to inspect anything. <\/p>\n\n\n\n<p>You could use the next button, the dot with a little curved arrow up and over it, to start &#8220;stepping&#8221; through the code. But Node is complicated, and you&#8217;ll soon find yourself in the bowels of Node doing god-knows-what. <\/p>\n\n\n\n<p>The trick is to put a <code>debugger;<\/code> statement in the code where you start caring about stuff. So&#8230;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"686\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.49.20%402x.png?resize=1024%2C686&#038;ssl=1\" alt=\"\" class=\"wp-image-1631\" style=\"width:597px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.49.20%402x.png?resize=1024%2C686&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.49.20%402x.png?resize=300%2C201&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.49.20%402x.png?resize=768%2C515&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.49.20%402x.png?w=1388&amp;ssl=1 1388w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>Now when I run again, I can hit the blue Play button and hop to this exact point the first time it gets there. <strong><em>Now<\/em><\/strong> I can start &#8220;stepping&#8221; through the code to see values. As I step through, I can see the values of relevant variables as I go. <\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"282\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-15.50.52.gif?resize=800%2C282&#038;ssl=1\" alt=\"\" class=\"wp-image-1632\"\/><figcaption class=\"wp-element-caption\">I can also hover over variables to see values as well as see locally-scoped variables in the sidebar on the right.<\/figcaption><\/figure>\n\n\n\n<p>Here I learned that when I declared the variable and then appended a string to it, I got that undesirable result. Lemme start with a blank string instead.<\/p>\n\n\n\n<p>We also essentially want to skip the last iteration of the loop. So instead we&#8217;ll use an old school <code>for<\/code> loop and run it over the length of all the words minus one. Then plop the last word (and !!!) at the end separately.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5) Restart Things Anytime<\/h2>\n\n\n\n<p>As I change my code, I can always <code>Control-C<\/code> out of the Node process and run it again, and DevTools (thank god) will automatically re-attach. <\/p>\n\n\n\n<p>Here I can start over and step through the code, seeing my changes yield the correct output.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"341\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-08-at-16.01.53.gif?resize=800%2C341&#038;ssl=1\" alt=\"\" class=\"wp-image-1633\"\/><\/figure>\n\n\n\n<p>The other debugger buttons (like the down arrow and up arrow) allow you to step through code quicker by fast forwarding to the next function call or finishing the function you&#8217;re currently in.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>This just feels like a more grown-up way to debug code when things get complicated. Especially for apps where you are jumping between lots of files, you can see all that happening in the DevTools file explorer on the left. <\/p>\n\n\n\n<p>Good luck out there! <\/p>\n","protected":false},"excerpt":{"rendered":"<p>I was pairing with my co-worker last week. They had a super different debugging style than I do. I&#8217;m aware that I can do fancy things in DevTools, like set breakpoints and whatnot right from within DevTools and use well-placed debugger; statements to halt JavaScript execution and inspect things at that point. But I hardly [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1635,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[65,147],"class_list":["post-1616","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-devtools","tag-node"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/mag-thumb.jpg?fit=1000%2C500&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/1616","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=1616"}],"version-history":[{"count":4,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/1616\/revisions"}],"predecessor-version":[{"id":1637,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/1616\/revisions\/1637"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/1635"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=1616"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=1616"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=1616"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}