Configuring VSCode to debug tools nested in a TypeScript app

Viewed 308

I'm trying to use VSCode to debug TypeScript files found within a larger app having dependencies on modules of that larger app, but I'm encountering errors such as:

  • SyntaxError: Cannot use import statement outside a module; OR
  • TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"

I've written an Electron/Svelte/TypeScript app for which I've partitioned core backend code into its own modules having no dependencies on Electron or Svelte. I've put all those modules in a directory I call 'kernel'. I also have a set of tools that run standalone from the app that depend on these core modules. I've put these in a directory called 'tools'. I can easily compile and run all my tools from the command line, but I have not been able to figure out how to run the tools from within the VSCode debugger.

My directory structure is basically this:

.vscode/
    launch.json
build/
node_modules/
public/
src/
    backend/
    frontend/
        tsconfig.json
    kernel/
    tools/
        tool-a.ts
        tool-b.ts
    electron.ts
package.json
rollup.config.js
tsconfig.json

I want to pull one of the tools (e.g. 'tool-a.ts') into VSCode, set breakpoints, and debug it. I have not yet found a way to do that.

The error I get depends on the configuration I try. But first, here's the configuration that I don't believe I should be changing, as the Electron app works just fine.

// package.json

{
  "name": "ut-spectool",
  "version": "0.1.0",
  "private": true,
  "main": "./build/electron.js",
  "scripts": {
    "build": "tsc && rollup -c",
    "build-client": "run-s build client",
    "build-backend": "tsc",
    "check": "svelte-check --tsconfig ./tsconfig.json",
    "server": "kill $(lsof -ti:5000) 2>/dev/null; rollup -c -w",
    "start": "sirv public --no-clear --single",
    "client": "tsc && cross-env NODE_ENV=development electron .",
    "dist:mac": "tsc && rollup -c && electron-builder build --mac --publish never",
    "test": "jest",
    "prettier": "prettier --config .prettierrc 'src/**/*.ts' --write"
  },
  "devDependencies": {
    ...
  },
  "dependencies": {
    ...
  },
  "build": {
    ...
  }
}
// top-level tsconfig.json

{
    "compilerOptions": {
        "sourceMap": true,
        "sourceRoot": "build",
        "target": "ESNext",
        "module": "commonjs",
        "outDir": "build",
        "stripInternal": true,
        "strict": true,
        "pretty": true,
        "moduleResolution": "node",
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "noImplicitReturns": true,
        "noFallthroughCasesInSwitch": true,
        "noEmitOnError": true,
        "allowSyntheticDefaultImports": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "esModuleInterop": true,
        "isolatedModules": true
    },
    "include": [
        "src/**/*"
    ],
    "exclude": [
        "node_modules/*",
        "build/*",
        "public/*",
        "src/frontend/*"
    ]
}

Here is one of the versions of launch.json I've tried, but "Launch Current Tool" gives me the exception, SyntaxError: Cannot use import statement outside a module, and the warning, (node:75650) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension:

{
    "configurations": [
        {
            "name": "Launch Current Tool",
            "program": "${file}",
            "request": "launch",
            "env": { "NODE_ENV": "development" },
            "console": "integratedTerminal",
            "preLaunchTask": "npm: build-backend",
            "outFiles": ["${workspaceFolder}/build/**/*.js"],
            "sourceMaps": true,
            "resolveSourceMapLocations": [
                "${workspaceFolder}/build/**",
                "!**/node_modules/**"
              ],
            "skipFiles": [
                "${workspaceFolder}/node_modules/**/*.js",
                "<node_internals>/**"
            ],
            "smartStep": true,
            "type": "pwa-node"
        },
        {
            "type": "node",
            "name": "vscode-jest-tests",
            "request": "launch",
            "console": "integratedTerminal",
            "internalConsoleOptions": "neverOpen",
            "disableOptimisticBPs": true,
            "program": "${workspaceFolder}/node_modules/jest/bin/jest",
            "cwd": "${workspaceFolder}",
            "args": [
                "--runInBand",
                "--watchAll=false"
            ],
            "sourceMaps": true,
            "skipFiles": [
                "${workspaceFolder}/node_modules/**/*.js",
                "<node_internals>/**/*.js"
            ],
            "smartStep": true
        }
    ]
}

(Mind you, debugging jest tests from within VSCode works just fine.)

Adding "type": "module" to package.json breaks Electron, so that's not an option. If I drop the following package.json into the tools folder...

{
  "type": "module"
}

... then attempting to debug tool-a.ts yields the error, TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/joe/repos/ut-spectool/src/tools/tool-a.ts. Hardcoding a "build" property in package.json for just one tool yields the same error.

If I change the value of program in launch.json to the following...

  "program": "${workspaceFolder}/build/tools/${fileBasenameNoExtension}.js",

... then when I debug via "Launch Current Tool", the program runs just fine in VSCode, displaying output in the VSCode terminal, but it ignores my breakpoints.

Other experiments I've done with launch.json have had no significant effect. For example, changing "type": "pwa-node" to "type": "node" (as used to debug with jest), does not change anything. I've also tried dropping a tsconfig.json into the tools folder and setting the "module" compiler option to "ESNext" and "ES6".

How do I get my nested tools running in the VSCode debugger?

0 Answers
Related