0

Goal

I would like to setup VSCode debugging for a create-react-app with Typescript. A couple years ago I used to work with Visual Studio 20XX and the debugging experience there was great, because you would not need to leave your IDE. I have been trying to replicate something similar every once in a while when I switched over to the Node ecosystem and Visual Studio Code, but I just haven't been able to succeed. Each method I have implemented either does not work reliably, or seems a bit cumbersome.

Ideally I would be able to press a single button resulting in an opened tab with the app in question.

Context

The project we are working on both has developers using Windows and OSX. A variety of browsers is used for local debugging, but it would be perfectly fine if a single browser is selected by VSCode. For this question I will focus on OSX, but ideally I would like to set it up for Windows as well.

Steps Taken

The VSCode documentation states that there are two different methods for debugging. Launching and attaching (here and here).

Launching

Originally it seemed like launching was the most in line with what I was after. This is the initial launch.json file that I setup with the documentation.

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "name": "Launch Chrome against localhost",
      "url": "http://localhost:3000",
      "webRoot": "${workspaceFolder}"
    }
  ]
}

While this worked, it opens a separate instance of Chrome or Brave (without browse history etc). Additionally, you still need to run npm run start and with create-react-app that opens a tab in your current browser instance. Theoretically the opening of the tab can be prevented, but this hinders a workflow that is already is used. So I would need to setup another start script.

This already feels a bit janky. Not only does a dev need to be aware of this all, but I think these will be barriers in its adoption.

Add preLaunchTask Therefore I decided to explore adding a preLaunchTask to this config. Unfortunately, I was not able to get this to work reliably.

    "start:v3": "export REACT_APP_OVERRIDE_VERSION=v3|| set REACT_APP_OVERRIDE_VERSION=v3&& npm start react-scripts start",
    "start:v3:background": "export BROWSER='none'|| set BROWSER='none'&& npm run start:v3",

launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      // Same as above
      "preLaunchTask": "npm: start:v3:background"
    }
  ]
}

tasks.json

{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "npm",
      "script": "start:v3:background",
      "group": {
        "kind": "test",
        "isDefault": true
      },
      "isBackground": true,
      "problemMatcher": [
        {
          "pattern": [
            {
              "regexp": ".",
              "file": 1,
              "line": 1,
              "column": 1,
              "message": 1
            }
          ],
          "background": {
            "activeOnStart": true,
            "beginsPattern": { "regexp": "." },
            "endsPattern": { "regexp": "." }
          }
        }
      ]
    }
  ]
}

There have been a number of problems with this approach:

  • The npm run start:v3:background script still opens a browser some of the time. I am unclear as to why the BROWSER=none is ignored.
  • Despite trying out different problemMatchers the background task doesn't reliably finish. Once it starts opening the browser (of the previous point) it never finishes.
  • Stopping the server after it starts seems difficult the approaches I have tried are either platform specific (OSX) or rely on executing VSCode functionality that does not work.

Question Is there any way of making this work? Or should I go the route of attaching? I feel there are some other downsides with that approach most notably that Chrome/Brave/Edge needs to be opened with --remote-debugging-port, which from what I can tell isn't easily done by default (i.e. to have Chrome always open with a debugging port) on OSX.

Eiter way I am at a complete loss as to how to make this work reliably. Any input would be greatly appreciated.

Fluous
  • 2,075
  • 2
  • 17
  • 29

1 Answers1

0

After finicking around with ChatGPT and some more blogposts, I finally managed to get something working reliably. The launch.json is largely unchanged, but I did add a postDebugTask.

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "name": "Launch Chrome against localhost",
      "url": "http://localhost:3000/",
      "webRoot": "${workspaceFolder}",
      "preLaunchTask": "start server",
      "postDebugTask": "stop server"
    }
  ]
}

These are the changes that I made in the tasks.json:

  • I moved the BROWSER=none environment variable to the tasks.json. This seems to work consistently, resulting in no additional browser window being opened and preLaunchTask now is considered finished, and no longer blocks the rest of the execution.
  • I changed the beginsPattern and endsPattern of the problem matcher based on this Stackoverflow post so that the browser is only launched after the preLaunchTask is finished.
  • Added a stop server script based on this blogpost to close the terminal running the server after the debugging has been stopped.
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "start server",
      "type": "npm",
      "script": "start:v3",
      "group": {
        "kind": "test",
        "isDefault": true
      },
      "isBackground": true,
      "options": {
        "env": {
          // Ensures that react-scripts does not open a browser.
          "BROWSER": "none"
        }
      },
      "problemMatcher": {
        "pattern": {
          // This is not needed but, required by the problemMatcher Object
          "regexp": "^$"
        },
        "background": {
          "activeOnStart": true,
          "beginsPattern": "Compiling...",
          // Ensures that browser is only opened after the task is completed.
          "endsPattern": "Compiled .*"
        }
      }
    },
    {
      "label": "stop server",
      "command": "echo ${input:terminate}",
      "type": "shell"
    }
  ],
  "inputs": [
    {
      "id": "terminate",
      "type": "command",
      "command": "workbench.action.tasks.terminate",
      "args": "terminateAll"
    }
  ]
}
Fluous
  • 2,075
  • 2
  • 17
  • 29