The Way of the Frontend Debugging

Jawakar Durai's avatar

Jawakar Durai

meme

Every developer wants to write good maintainable code, where there are zero bugs, and nothing creeps in. But, that's not the case. Bugs are inevitable. So, it is important to learn how to debug them.

The way we debug our code/issue is very important. It can make or break our productivity. In this post, I will share my debugging workflow without going into too much theory.

I always believe storytelling is the best way to learn. So, I will try to explain the flow by telling a couple of stories.

Some theories first:

  • What: Understand the issue, what is expected and what is happening
  • Where: Which pages and environments it’s happening, is it only in prod? or all envs?
  • When: Sometime it’s very easy to figure out the file/code which is caused the issue, could be something we changed recently. But, sometimes it’s not that easy. So, we need to figure out the commit which caused the issue. and then find the file/code which is causing the issue.

Most of my daily work is working with React and Gatsby. So, I will be using those as examples.

1. Debugging a redirection issue

Setup

Our setup is, we use gatsby cloud for preview URLs and as a dev environment and Netlify for production deployment due to some future business needs, previously the production is set up in a different ec2-like machine.

We recently migrated to Netlify and we also migrated all the thousands of redirects to be used with Netlify. By just putting our _redirects in the static folder and also creating redirects in the gatsby cloud using the createRedirect API.

The issue

There is an error report saying that redirections are going wrong for a couple of paths. From prod.com/verification/<some_id>?source=website it is redirecting to prod.com/verification/*?source=website literally * not wildcard, instead of v1.prod.com/verification/<some_id>?source=website.

The debugging

Okay, to start from, we have the issue and we got to know it's happening only on production env, not in gatsby cloud.

The first place to start the investigation is _redirects as we know that recent changes are related to redirections. So, I checked the file and it looked fine.

We have the redirection in the _redirects file

/verfication/* https://vi.prod.com/verfication/* 301

And in gatsby cloud, it works where we read the _redirects file and create the redirections using the createRedirect API.

This implies the issue could be related to wildcarding in Netlify. Let's dig for more info on this in Netlify docs. I couldn't find the exact documentation but found in some other docs related to redirection that they use :splat instead of * for wildcarding. The search for more docs led me to this answer from netlify team. Now it's clear we need to use :splat instead of * for wildcarding.

Woof!! But the issue doesn't end here, we need to check if :splat is supported in gatsby cloud as well. As it turns out, gatsby cloud doesn't support it, making it impossible for us to use :splat in both gatsby cloud and Netlify.

The solution is * for Gatsby but :splat for Netlify for to path. We could use :splat in _redirects and when reading and creating redirections in gatsby cloud we can replace :splat with *.

Should I reinvent the wheel and maintain it? Nope! I found that gatsby-plugin-netlify does this for us, we just need to create redirections using createRedirect API and the plugin will create _redirects file for us.

2. Assumption is your enemy

This is just a workflow to a super simple issue you could encounter while implementing a feature, debugging is not only for the bugs reported from the users/managers. It's also for the bugs that creep in while implementing a feature.

The feature

We wanted to use gatsby-plugin-image for our gatsby site. You get some image from the query and render it in <GatsbyImage />. Gatsby allows you to add a placeholder and generate AVIF image format. For that, you have to modify the query or pass props every time. Instead of repeating this every single time, we can simply pass defaults when we’re adding the plugin like this:

{
  resolve: `gatsby-plugin-image`,
  options: {
    defaults: {
      images: {
        placeholder: `blurred`,
        formats: [`auto`, `webp`, `avif`],
      },
    },
  },
}

The issue

I have added gatsby-plugin-image exactly as explained in the documentation, but it didn’t work.

I opened react devtools to see the props that are passed to internal components of <GatsbyImage /> and found that placeholder is undefined. And the avif images are not even generated at the build time. It's like the plugin is not even taking my options.

I did a silly mistake of assuming we need to add the options to gatsby-plugin-image instead of gatsby-plugin-sharp. I didn’t even check the plugin name on the docs. I just assumed :(

I’m not sure if anybody has done this. But it took more than 10 mins and rerunning the build couple of times to realise this.

So you shouldn't assume? You can make lots of assumptions but you should always check them. Once you assume something and make something work, you should always go back and validate your assumptions.

Debugging tools

Sometimes it’s very hard to debug something, let’s say you add something to the build process that’s handled by a framework and it didn’t work

But we should at least use what we already have:

React dev tools

  • Check the props you pass
  • See the current state
  • The magic wand to see state names (Recent one)
  • See custom hook states
  • You can Highlight components on rerender

Effectively using devtools can reduce the amount of time you spend on debugging something.

For small performance improvements, you could use profiler to see if some unwanted component is being re-rendered.

Inspector

  • See the rendered HTML is what we expected
  • Debug style, CSS-related issues
  • Use flex and grid highlighting
  • Try quick css fixes just by adding classes and style in the inspector

You can use Inspector to it's full potential, directly edit html to see how duplicating the elements affects the layout, how it's gonna look if we have longer/shorter text? Possibilities are endless.

Breakpoints

  • Learn about breakpoints on the debugger
  • Add Breakpoints on lines you want to debug
  • You can enable Pause of exceptions to see the state of the code at the time of exceptions
  • Add breakpoints on any events to debug events-related issues

Console

The browser will help you in all the ways it can to make you debug fast, gives you the file and line the error has occurred (Sometimes this can go for a toss), gives you a stacktrace of the issue, and enables you to dig deeper into any issue.

Console log vs Debugger

Everybody started from console.log() but that is not all. If you start using the debugger’s breakpoints, you’ll never go back to console.log(). You can also add breakpoints to any package code in the browser to check what’s happening, believe me this will happen a lot.

All done

There are also other options like asking for help from a colleague or a friend, if nothing works there is a community for all the frameworks and languages, and you can ask for help there. And sometimes giving a break and walking away for some time and coming back will help you.

These tools are there to help us debug better. We should treat debugging as a skill and sharpen it as we grow to be more productive.