How to Enable Breakpoint Debugging with TypeScript, webpack, VS Code, and Chrome

This article is a translated version of my original post on Qiita. Original (Japanese): https://qiita.com/segur/items/2119ad054d98a06c5929

How to Enable Breakpoint Debugging with TypeScript, webpack, VS Code, and Chrome

To perform breakpoint debugging in the environment mentioned in the title, you'll need to overcome several hurdles.

Even a single misconfiguration can lead to "Why isn't it stopping at the breakpoint?!" That's why I'll carefully explain what settings are necessary.

Prerequisites

Ensure the following environment is already set up:

Setting Up Breakpoint Debugging

Edit tsconfig.json

Edit tsconfig.json to enable source maps for TypeScript. This allows the mapping of TypeScript before the build to JavaScript after the build.

tsconfig.json

{
    "compilerOptions": {
        "sourceMap": true
    }
}

Edit webpack.config.js

Edit webpack.config.js to enable source maps in webpack. This links code before and after bundling.

If you have different configuration files for different environments, like webpack.dev.config.js or webpack.stg.config.js, it's a good idea to create a dedicated configuration file like webpack.debug.config.js. We'll use webpack.debug.config.js from here on.

webpack.debug.config.js

module.exports = {
    mode: "debug",
    devtool: 'inline-source-map',
    devServer: {
        index: "index.html",
        port: 9223,
        historyApiFallback: true,
    }
};

Here, the port is set to 9223, which is the debugging port. While it's not mandatory to use this number, avoid using 3000 or 8080 to prevent mix-ups with regular development ports.

Install Debugger for Chrome in VS Code

Install the following extension:

Debugger for Chrome

Create launch.json

Create a .vscode/launch.json file. This is the debug configuration file for VS Code.

launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch Chrome",
            "type": "pwa-chrome",
            "request": "launch",
            "url": "http://localhost:9223",
            "webRoot": "${workspaceFolder}",
            "sourceMapPathOverrides": {
                "webpack:///./*": "${webRoot}/react/*",
            }
        }
    ]
}

Setting the Type

"type": "pwa-chrome" launches a debugger for Chrome. You can also use "type": "chrome". Since pwa-chrome is a newer debugger, it's recommended to use it if you have no specific preference. For more details, refer to What is the pwa-node type launch configuration on VSCode?.

Setting the URL

Specify the same port number as in webpack.debug.config.js with "url": "http://localhost:9223".

Setting sourceMapPathOverrides

sourceMapPathOverrides links folders in VS Code to source locations in the browser. This configuration can be quite difficult—it's the toughest part! In the sample, it's "webpack:///./*": "${webRoot}/react/*", but it varies based on your project's folder structure. For example, if the folder containing package.json is called app or server, adjust accordingly. For a clear guide, see VSCodeのDebugger for ChromeにおけるsourceMapPathOverrides設定メモ.

Create settings.json

If not already present, create a .vscode/settings.json file, which is the editor's settings file for VS Code.

settings.json

{
    "debug.javascript.usePreview": false,
    "debug.allowBreakpointsEverywhere": true
}

Set debug.javascript.usePreview to false as breakpoints might not work with true.

Set debug.allowBreakpointsEverywhere to true since breakpoints might not be effective with false.

Launch Debug with webpack-dev-server

Execute the following command:

webpack-dev-server --config webpack.debug.config.js -d

This will start the web server in a state ready for debugging.

Try Breakpoint Debugging in VS Code

Set breakpoints at any desired line in your TypeScript code. Press F5, and Chrome should launch. When you interact with Chrome and execute the code with breakpoints, the debugger should stop at those breakpoints! If it doesn't stop, review your settings up to this point.

Automating the webpack-dev-server Command

It's convenient to be able to do breakpoint debugging, but typing the webpack-dev-server command every time is cumbersome. Let's automate this process.

Edit package.json

Add an NPM Script to package.json.

package.json

{
    "scripts": {
        "debug": "webpack-dev-server --config webpack.debug.config.js -d"
    }
}

This allows you to run npm run debug to start webpack-dev-server in debug mode.

Create tasks.json

Create a .vscode/tasks.json file, which describes pre-launch processes for launch.json.

tasks.json

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "npm: debug",
            "type": "npm",
            "script": "debug",
            "path": "react/",
            "isBackground": true,
            "problemMatcher": {
                "owner": "custom",
                "pattern": {
                    "regexp": "^$"
                },
                "background": {
                    "activeOnStart": true,
                    "beginsPattern": "yarn run.*",
                    "endsPattern": ".*Compiled successfully.*"
                }
            },
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

Create a task named npm: debug.

To ensure npm run debug doesn't exit during debugging, set "isBackground": true. Define problemMatcher to signal when preparation for debugging is complete so VS Code can understand this.

Details of problemMatcher

In my setup, webpack-dev-server output includes yarn run at the start, which signals the start of the task, so it’s specified as beginsPattern. Adjust this to fit your environment. Similarly, upon completion, it outputs Compiled successfully, which is set as endsPattern. Modify for your setup as necessary.

These settings were inspired by:

Edit settings.json

Edit the .vscode/settings.json file created earlier.

settings.json

{
    "debug.javascript.usePreview": false,
    "debug.allowBreakpointsEverywhere": true,
    "terminal.integrated.shellArgs.linux": [
        "-l"
    ]
}

Added terminal.integrated.shellArgs.linux to ensure your OS environment variables are reflected in the VS Code shell, allowing npm path access from tasks.json.

Edit launch.json

Edit the .vscode/launch.json file created earlier.

launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch Chrome",
            "type": "pwa-chrome",
            "request": "launch",
            "preLaunchTask": "npm: debug",
            "url": "http://localhost:9223",
            "webRoot": "${workspaceFolder}",
            "sourceMapPathOverrides": {
                "webpack:///./*": "${webRoot}/react/*"
            }
        }
    ]
}

Added "preLaunchTask": "npm: debug" so that webpack-dev-server automatically runs as a pre-launch task during debugging.

That's it! Now your automation setup is complete. Well done!

In Conclusion

The creation of this article was inspired by the following references. Thank you for the clear explanations: