KINDERAS.COM

Debugging a Next.js project in Visual Studio Code

Mon Oct 04 2021

Nextjs is the most popular of the «JAMStack» site generators. Next combines build time rendering with serverside rendering and some «in-between» features like server rendering and caching on request.

Since Next is such a versatile tool, it isn't always straight forward how to debug your code. So, in this aricle I'll walk through setting up debugging both for the server rendering part and the client (in the browser).

Setting up debugging for Visual Studio Code

The first thing you'll need to do is to do it to tell webpack how to generate the correct devtoolModuleFilenameTemplate. This is done by editing the next.config.js file.

Your next.config.js file should look something like this.

/** @type {import('next').NextConfig} */
const webpack = require("webpack");
module.exports = {
    // ... your config

    // This is for debugging to work
    webpack(config) {
        config.output = config.output || {};
        config.output.devtoolModuleFilenameTemplate = function (info) {
            return "file:///" + encodeURI(info.absoluteResourcePath);
        };
        return config;
    },
};

The next step is to add a debug script to your package.json file. This script will be used later in the launch config. You can name this script whatever you want, I'm using «debug» for this example.

{
    "name": "...",
    "version": "1.0.0",
    "scripts": {
        "dev": "next dev",
        "debug": "set NODE_OPTIONS=--inspect&&next",
        "build": "next build",
        "start": "next start"
    },
    "dependencies": {},
    "devDependencies": {}
}

Now let's move on to the launch config. Create a new launch confor from the VSCode debug menu and add the following:

Notice that we are reffering to the «debug» npm script in the «Next: Node» config.
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Next: Edge",
            "request": "launch",
            "type": "pwa-msedge",
            "url": "http://localhost:3000",
            "webRoot": "${workspaceFolder}"
        },
        {
            "type": "node",
            "request": "launch",
            "name": "Next: Node",
            "runtimeExecutable": "npm",
            "runtimeArgs": ["run", "debug"],
            "port": 9229,
            "console": "integratedTerminal"
        }
    ],
    "compounds": [
        {
            "name": "Next: Full",
            "configurations": ["Next: Node", "Next: Edge"]
        }
    ]
}

There are two configs here and one compound config letting you start both at the same time.

  1. «Next: Edge» - This will launch the Edge browser (this requires the Edge plugin for VSCode). You can also use the older Chrome debugger for this if you want.
  2. «Next: Node» - Start this to debug any server side stuff, such as logic inside «getStaticProps» and so on.

How to debug

This part is pretty straight forward. Just set breakpoints within VSCode and trigger them. Note that if you are debugging functions like «getStaticPaths» and others that run at launch, it might be a good idea to set the breakpoints before you trigger the launch config.

That's it. Happy debugging.

Reducing Gatsby HTML file size by removing inline styles

Sat Aug 28 2021

The static/dynamic site generator Gatsby is a great tool for generating semi-static websites. However, if you are using CSS modules and CSS frameworks like bootstrap (or just have a lot of CSS), then individual HTML files can become quite large.

Why does this happen

When Gatsby builds a page it tries to make sure that every pages is as "standalone" as possible. Meaning that the user could request a page at any path and still get a fast response. To achieve this Gatsby will bundle all of your CSS needed for that page into an inline style tag. The idea is that this will make it unnecessary for the browser to load an external stylesheet before drawing the page. That's actually a good idea, but a bug/oversight in the Gatsby bundler will (at the time of writing this) cause all of the CSS to be bundled into every page. This is a known issue and the people working on Gatsby will probably fix it, but in the meantime, here is how you can fix this today.

How to remedy this problem

The fix do involve removing inline styles from each page and relying on an external stylesheet instead. In modern browsers supporting http2 loading this extra file shouldn't affect loading performance much.

Here's how to remove the inline style from each HTML page.

In gatsby-ssr.[js|jsx|tsx] add the following (note that this is Typescript):

import { PreRenderHTMLArgs } from "gatsby";

export const onPreRenderHTML = ({ getHeadComponents }: PreRenderHTMLArgs) => {
	if (process.env.NODE_ENV !== "production") return;

	getHeadComponents().forEach((el: any) => {
		if (el.type === "style" && el.props["data-href"]) {
			el.type = "link";
			el.props.href = el.props["data-href"];
			el.props.rel = "stylesheet";
			el.props.type = "text/css";

			delete el.props["data-href"];
			delete el.props.dangerouslySetInnerHTML;
		}
	});
};

This piece of code will replace all inline styles with a link to the stylesheet instead. Note that it will only run when using gatsby build, if you want it to run for development just remove the first line of the `onPreRenderHTML` function.

Sources

Using Visual Studio Code (VSCode) to debug Parcel and Gatsby projects

Sat Jun 12 2021

Being able to properly debug projects within your favorite editor/IDE is an essential part of being a developer.
In this post I'll take you through setting up Visual Studio Code (VSCode) in way that allows you to debug your code directly within VSCode when working with the page generator Gatsby (https://www.gatsbyjs.com) and projects build with the Parcel bundler (https://parceljs.org). This works for both Typescript and regular JavaScript projects.

Debugging projects generated with the Parcel bundler

The goal here is to be able to set breakpoints in our code files in VSCode, then launch Chrome from VSCode and perform the debugging steps all from within the VSCode editor. This should work with Typescript projects, JavaScript projects and React Projects.

Steps

  • First you'll need to install the "Debugger for Chrome" extension for Visual Studio Code (msjsdiag.debugger-for-chrome)
  • The next step is to configure a launch configuration (see below).
  • Add an npm script to start parcel, e.g: "start": "parcel src/index.html".
{
	"version": "0.2.0",
	"configurations": [
		{
			"type": "chrome",
			"request": "launch",
			"name": "Launch Chrome debugger",
			"url": "http://localhost:1234",
			"webRoot": "${workspaceFolder}",
			"breakOnLoad": true,
			"sourceMapPathOverrides": {
				"../*": "${webRoot}/*"
			}
		}
	]
}

Debugging

  • Run the npm script first, in this example it would be npm start
  • Now you can start debugging in VSCode by running «Launch Chrome debugger» from the «Run and debug» menu
  • Chrome will open and you can set breakpoints within VSCode

Debugging Gatsby projects within Visual Studio Code (VSCode)

There are two separate steps to a Gatsby project you might like to debug, the build phase and/or the runtime phase.
The full launch config for both phases can be found at the bottom of this post.

Debugging the Gatsby build phase from Visual Studio Code (VSCode)

The build phase in a Gatsby project is when Gatsby is generating all pre-generated content, such and pages etc.
In this phase you'll mainly focus on debugging the «gatsby-node.[js|ts]» file, and of course any file you refer to.
Since this step in Gatsby is executed by Node, this is just like debugging a Node application. Works for both JS and Typescript Gatsby projects.

  • If you are using Typescript, set "sourceMap": true in the «tsconfig» file.
  • Add a new config to your launch.json config file in VSCode (see below)
  • Set a breakpoint in your «gatsby-node» file and run the launch config below
{
	"name": "Debug gatsby-node",
	"type": "pwa-node",
	"request": "launch",
	"program": "${workspaceRoot}/node_modules/.bin/gatsby",
	"args": ["develop"],
	"stopOnEntry": false,
	"runtimeArgs": ["--nolazy"],
	"console": "integratedTerminal"
}

Debugging the runtime React part of a Gatsby project from within Visual Studio Code (VScode)

The runtime phase is where you'll want to debug any client side React and Typescript/JavaScript code. This setup is very similar to the Parcel setup at the start of this post. Let's go though the steps:

  • If you haven't done this already, install the "Debugger for Chrome" extension for Visual Studio Code (msjsdiag.debugger-for-chrome)
  • The next step is to configure a launch configuration (see below).
  • Setup a npm script to start the Gatsby server: "start": "gatsby develop"

{
	"type": "chrome",
	"request": "launch",
	"name": "Launch Chrome debugger",
	"url": "http://localhost:8000",
	"webRoot": "${workspaceFolder}"
}

Debugging the runtime React app

  • To debug you can now run the npm script npm start and when it's done (might take a while) ...
  • Now you can start debugging in VSCode by running «Launch Chrome debugger» from the «Run and debug» menu

Full launch config for both Gatsby phases

{
	"version": "0.2.0",
	"configurations": [
		{
			"name": "Debug gatsby-node",
			"type": "pwa-node",
			"request": "launch",
			"program": "${workspaceRoot}/node_modules/.bin/gatsby",
			"args": ["develop"],
			"stopOnEntry": false,
			"runtimeArgs": ["--nolazy"],
			"console": "integratedTerminal"
		},
		{
			"type": "chrome",
			"request": "launch",
			"name": "Launch Chrome debugger",
			"url": "http://localhost:8000",
			"webRoot": "${workspaceFolder}"
		}
	]
}

QuickTip: Css only tool tip

Thu Aug 27 2020

Tool tips can sometimes be useful to display things like help texts and similar. This post demonstrates how to create a tool tip without any JavaScript, only using HTML and CSS.

Example - Tooltip on hover

This example uses the hover event. This does work (isj) even on touch devices, but it's a good idea to provide a fallback.
<div>
	<a href="https://test.com" data-tip="This is a tooltip"> Hover over me. </a>
</div>

The html is just an anchor tag inside a div. The anchor tag has a data attribute called «tip», this is will be used as the source for the tooltip content.

First selector - «a[data-tip]»

All of the CSS rules uses attribute selectors. You don't need to use attribute selectors, but it makes it easier to target only those `a` elements that has tool-tip data attached.

a[data-tip] {
	position: relative;
	color: #00f;
}

This selector targets the anchor tag itself. The only required property here is position:relative, this is needed to gain a working starting position for the tooltip.

Second selector - «a[data-tip]:hover/focus::after»

a[data-tip]:hover::after,
a[data-tip]:focus::after {
	content: attr(data-tip);
	position: absolute;
	left: 0;
	top: 24px;
	min-width: 200px;
	border: 1px black solid;
	border-radius: 5px;
	background-color: rgba(0, 0, 0, 0.5);
	padding: 12px;
	color: white;
	font-size: 14px;
	z-index: 1;
}

This is where it all happens. The main thing making this work is the ::after pseudo selector. When used with the content property it will insert a pseudo element as the last child of the selected element. In this example it adds the tooltip text as a child element to the anchor tag.

  • «content: attr(data-tip)» sets the content of the tooltip to the content in the «tip» data attribute.
  • «position:absolute» and the «left/top» values sets the position of the tooltip relative to the anchor tag
  • The rest of the css is mostly styling the tooltip.

How does this example work on touch-devices?

Hover doesn't exist on touch devices. However, browsers have implemented the hover action to trigger on first tap. So, when the user taps the hover target, the hover event will trigger, on the next tap any other events (like click for links) triggers.

References and links

QuickTip: Using CSS «line-clamp» to truncate text to a set number of lines

Sun Aug 02 2020

When working with dynamic text content it can be quite useful to be able to truncate the number of text lines displayed in a HTML element. This can be done using the CSS `«line-clamp»` property.

The resulting line trucation
The resulting line trucation

Consider the HTML below. We have a div with a paragraph inside containing some text.
For this demo we want to show max 3 lines of text in this div element.

<div class="content">
	<p>
		Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec venenatis velit sit amet dui semper dignissim.
		More dynamic text here.
	</p>
</div>

Lets say the max width of the `content` div is 200 pixels and max of 100 pixels in height.

.content {
	width: 200px;
	height: 100px;
	padding: 10px;
}

We want to truncate all text over 3 lines.
Here we set the display to «-webkit-box» and the «-webkit-line-clamp» property to 3 lines of text.

.content p {
	display: -webkit-box;
	-webkit-line-clamp: 3;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

Resources