6 ways to turn your browser into super-debug-hero (ft. node.js + next.js!)

6 ways to turn your browser into super-debug-hero (ft. node.js + next.js!)

Unlike some of my other posts, this one is going to be straight-forward.

I’ll cover some of the less-frequently-used browser devtools features that I’ve used over my career.

Some basic things are excluded, so as to not completely waste your time.
Things such as using “console.log”, editing CSS in the styles panel, editing HTML in the Elements tab, $0 element reference, etc.

Table of contents:

Breakpoints
Performance Profiling
Responsive Mode
Lighthouse
Layers
Console.notJustLog

Bonuses:

Node.js debugging + typescript
Next.js server side debugging

Let’s go! 🚀🚀🚀

1. Breakpoints! [🔝]

My goodness this was the first debugging thing that blew my mind about why debuggers are actually useful.

The idea is simple. Code, is written line-by-line.
When you’re trying to spot bugs, you’re following the flow of execution line by line.
Variables are assigned values, functions are called, loops run, etc. which all reads or writes data from places.

You’ll find this thing in the SOURCES tab in DevTools.

And by placing breakpoints you can see the state of your code, and the data contained within to understand how your code is actually running.
Makes it a lot easier to find bugs! It’s a LOT faster than placing a million console.logs everywhere. You can even modify the values in memory at your breakpoint!


It’s literally as simple as double-clicking a value to change it! (in most cases)

For further reading: Pause your code with breakpoints  |  Chrome DevTools  |  Chrome for Developers

2. Performance Profiling [🔝]

“Why does this action take longer than it should? It’s not like I’m making any API calls here.”

Code (sometimes) works in mysterious ways.
Obviously it shouldn’t, but often you’ll find yourself in legacy codebases, or just repos that became a bit of a mess over time. Features or actions that should seem super straight-forward in how they work, somehow end up causing a lag on the UI, trigger re-renders, multiple API calls, or what not.

When you run into situations where user interactions (not async stuff) aren’t happening “near-instantly” on the UI, you’re probably putting the CPU under too much load.

Examples when this could happen:

Modifying a large list of items
Calculating some stats from a dataset, on the browser
Complex map/filter/reduce usages
Browser-side search over a dataset

One option is to understand where that “blocked time” is being spent.
Presenting, the “Performance Profiler”! Present in the “Performance” tab in your devtools! (who could have guessed?)

You’ve already seen the screenshot above, but did you know you could also set up limits on how fast your CPU should be, and how many cores can it used at the same time?

You can also open the “Sources” panel to literally look at the source files to understand exactly which lines all this time is being spent.

Unfortunately, if you have an intermediate build step, like webpack, rollup, etc. this feature might not be that directly useful, since your JS code would be “compiled” (or “transpiled” if you prefer calling it that) into something that looks pretty different.


Look at it! I clearly have some recursive call issues combined with some CPU heavy logic going on. And because of the “Sources” panel above, I can see it’s happening because I created a pretty large for loop just for the sake of this example. 😄

3. Responsive Mode (aka. Device Mode) [🔝]

There’s a 99.8765% chance you know what this is.
Most of the internet traffic comes from Mobile devices now. There’s no way you haven’t resized your browser window a million times to see how it looks on different devices.

But responsive mode is a lot more configurable than most people are aware of.
Generally people stick to the device presets. It’s a dropdown that looks kinda like this:

However, it often feels insufficient to tell you how to actually see how comprehensive your media-query handling is, what breakpoints your web-app uses, and just leaves it kinda complicated to understand how your app will work on all kinds of devices…
Again, I’m talking about what happens if you stick to only the presets.

Unlocking the full potential of “Responsive Mode”

See the small 3-dot menu at the top when you enable “Responsive Mode”?
Once you open that menu, just “show” all kinds of things that it lets you enable.
And finally, set the Dimensions dropdown value to Responsive.

This is what you can do now:

Media Queries
It’ll show you what media queries are used in your web-app. Clicking on them will resize the viewport to the selected width. I’m unsure if there’s a way to do this with height as well, but if you know, please leave a comment. 😃

Rulers
No guessing what your current viewport width is. A nice ruler along both axes tells you… well… exactly what you expect it to tell you.

Device Pixel Ratio
This is something that wouldn’t really bother you in your day-to-day, because the browser kinda automatically handles it.
But what this option is, is how many hardware pixels are needed to render a single software pixel.
Sorry, I won’t go too deep into that topic in this post, but MDN has you covered:
Window: devicePixelRatio property – Web APIs | MDN

This property particularly becomes relevant when you’re using the HTML Canvas for something.

Device Type
This is more of a useragent type thing. Changing this value tells the target server/website what kind of a device is the page being accessed from, and whether that device supports touch or not.

Various sites handle UIs for web and mobile very differently.

You can even resize it very conveniently without having to resize the whole window, by dragging the corner at the bottom-right.

4. Lighthouse (and Core Web Vitals) [🔝]

In case you missed it, Lighthouse is a tool to inform you about the overall “quality” of your webpage. You could NEVER guess what tab you’ll find this under. (Hint: It rhymes with Bright-house)

What’s covered under quality?

Page loading performance and experience
Accessibility of the page for people with certain restrictions
SEO (aka. how well it might show up in search results)
And other “best practices” stuff

The general idea is, the higher your lighthouse score is, the better:

The experience of your users will be
The visibility on search results will be

Better visibility + More users == Money (usually)
So, it might be important to you.

Lighthouse an give you pretty comprehensive data on how you can improve your page even further!


5. Layers Inspector [🔝]

“Why does my modal show up on top of this tooltip?”
“Why does this button show up on top of this overlay?”
Layers Inspector is one of the coolest looking features in your browser, that allows you to:

See the stacking context of your elements
Understand if there are elements unintentionally rendered under or over other elements
Identify performance issues in certain layers
View elements that may be getting partly or wholly rendered off-screen
And most importantly… Feel super cool about your work. I mean… look at this thing!

P.S.: Edge calls it 3D View, but it’s a slightly differently functioning feature as well that still achieves many of the same things.

Story-time:

Most recently we realized that our product landing page had a bug where each individual image and the menu item was rendered twice, exactly stacked on top of each other in a way that visually you couldn’t tell anything was wrong.

I was investigating something in the menu that looked off as a result because I was introducing some transparency styling which made the menu look weird.

Decided to Cmd+Shift+C and check the element styles. Nothing particularly off. But I noticed that there were two instances of that element.

Now I decided to check the Layers Inspector, and wouldn’t you look at that! Our static site builder caused there to be duplicate instances of a lot of other images too! Thanks layers!

6. Console.notJustLog [🔝]

Did you know…
console.log is such a 2015 way of debugging at this point?

There are a LOT of things that the console object allows you to do.
Here’s a screenshot of all the things included within it!

tl;dr: Go read this: console – Web APIs | MDN

I’m going to cover my top 5 features under console.

1. console.table is nuts!
This is hands down one of the nicest ways to visualize most kinds of basic objects. It kinda doesn’t work too well when it comes to deeply nested objects, but, you know, for most objects it works fine enough!

2. console.group helps with limiting logging overload for your eyes
Okay, no one is getting rid of console.log. But there are times when you might need to log a few too many things, and then the actually useful information starts to get lost in a sea of other not-so-useful logs.
console.group allows you to nest your logs within groups that may be multiple levels deep!

P.S.: There’s also console.groupCollapsed if you don’t want your groups to be open by default.

3. console.assert for conditional logging
If you’ve ever done something like:

if (mycondition) console.log(Log stuff)

You could make use of console.assert instead.

It only logs when the first argument is false.

4. console.count for “incremental” logging
Ever felt the need to check how many times a certain function got invoked, or just some logic ran, maybe understand how often a certain useEffect got triggered?
Here you go.

You don’t have to pass it a static string like count label either.
Pass it something like user.id or whatever is stored in your objects or variables, and you’ll see how many times your logic runs with those specific values.

For example, how many times did my useEffect get triggered while the user ID was 1001-1234? That’s something you can answer with console.count(user.id) instead!

5. console.trace to understand how your functions get called
Functions. They can get called anywhere, and everywhere.
Sometimes it can be confusing to understand how a specific function actually gets called. Where it gets called from. This is going to be helpful for that.

BONUS: console.log. With *flair!*
Sometimes the plain-old plain-text just isn’t enough for your needs… for those times, you have this:

console.log(%cRed Text, color: red;);
console.log(%cGreen Text, color: green;);
console.log(%cBlue Text with Larger Font, color: blue; font-size: 18px;);
console.log(%cStyled Text, color: white; background-color: black; padding: 2px;);

[BONUS] 7. Node.js Debugging, in Chrome?! [🔝]

You can do it for both Javascript AND Typescript files!
“What? Really? I had no idea!! But how is that even possible?!?”
Okay, too much, I know.
If this is already familiar with you, I would love to hear how YOU use node.js debugging in your browser, and if there’s an awesome new idea that I didn’t know about, I’ll add it to the post! (attributed to you of-course)

But for a lot of folks that don’t know that this is possible, here you go…

Start your node server using the –inspect flag. node –inspect index.js

If you’re using tsx by any chance, it works in the same way. tsx –inspect index.tsx

Go to chrome://inspect/#devices. If you’re on a chromium based browser (edge, brave, arc), this URL should work.

You should see something like this.

Click on inspect

You should see a new window open that looks something like this:

You’ll notice that I was able to print the value of process object.
That’s because this instance of devtools is running in the context of node.js

That’s it!
Just like how you can debug browser side code, you an also debug server side code with this.

Look at me placing a debugger and all!
Note: See the two xmas.ts and utils.ts files? One of each of those is a “sourcemap” file.
Curious about what THAT project is? Check it out!
jayantbh/xmas-cli: Christmas tree generator

[BONUS/2!] 8. Next.js Server Side debugging?! [🔝]

Oh yeah! You can use all the capabilities of your Chrome Devtools to debug your Next.js applications server side logic. And it’s as simple as 1, 2, 3!

Pre-requisites: You have a nextjs app set up locally and all packages installed.

Run NODE_OPTIONS=’–inspect’ yarn dev or NODE_OPTIONS=’–inspect’ npm run dev

Wait till the logs say something like:

Debugger listening on ws://127.0.0.1:9230/3473fa37-03ec-4dc9-9769-3fd97998f0b7
For help, see: https://nodejs.org/en/docs/inspector

Go to chrome://inspect/#devices and inspect the target that represents your app

You might see something like this:

In this case, the one with next/dist/server/lib/start-server.js is the one I need to inspect

An instance of DevTools will open.

Load your app! Go to localhost:3000 or whatever you app is supposed to load on. That’s it!

At the start you might not see any files related to your app in the sources panel, but as you load parts of your app, it’ll begin to show up in devtools.
Once it does, you can place breakpoints, see in-memory values, change things, etc!

Hope you found this useful. 🎉
I would love to hear other awesome ways you use your browser as the worlds greatest debugger, client-side or server side, in the comments! 😃