NodeJS Debug & VSCode Debugger

A,Debugging

1.DebugThe debugger

  1. Debugger configuration management;
  2. Debugger start, stop, step operation;
  3. Source code, functions, conditions, breakpoints, and log points;
  4. Stack tracing, multithreading and multiprocess support;
  5. In the view andhoverBrowse complex data structures in the
  6. Variable values are displayed inhoverAnd source code;
  7. watchExpression management
  8. Debug console for automated interactive evaluation.

2. Start debugging

1. Create onetestvscodedebugDirectory in which to createindex.jsfile

const a = '1';
const b = '2';
debugger;
for(let i = 0; i < 10; i++) {
    console.log(i);
}

const arr = [1.2.3.4.5];

const isTrue = arr.some(item= > {
    console.log(item);
    return item > 4;
});

console.log(isTrue);
Copy the code

2. Click the debug button

You need to createlaunch.jsonfile

3. Click the “Create launch.json” button and selectNodeJS

You will notice that there is an extra one in the folder.vscodeThere’s a folder in itlaunch.jsonfile

4. Click Debug again

Start debugging

5. Debug the toolbar

● Continue/Pause F5 ● Jump over F10 ● Step into F11 ● Go out registering F11 ● Restart registering F5 ● Stop registering F5

6. Red dot debugging

You don’t have to add it to the codedebuggerAdd red dots on the side of the code to debug.

7. Log

Right-click on the red dot in each row and select Add Log PointFor example: This log point records in the loopiValue:{i} As you execute, you can see that logs are printed.

3,Launch.jsonattribute

1. Static configuration

{
    // Use IntelliSense to learn about related attributes.
    // Hover to view descriptions of existing properties.
    / / for more information, please visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0"."configurations": []}Copy the code

2. configurationsconfiguration

interface common {
  // Environment type, such as node
  type: string
  / / the debug mode
  request: 'launch' | 'attach'
  // Debugger name The name displayed in debugger management
  name: string
  // Follow the protocol
  protocol: 'auto' | 'inspector' | 'legacy'
  // debug port
  port: number
  // Debug the TCP/IP address of the port
  address: string
  // Enable source mapping by setting this to true
  sourceMaps: boolean
  // An array of glob patterns used to locate generated JavaScript files
  outFiles: array
  // Restart the session on termination
  restart: boolean
  autoAttachChildProcesses: boolean
  // When restarting the session, abort after this number of milliseconds
  timeout: number
  // Interrupt immediately when the program starts
  stopOnEntry: boolean
  // VS Code's root directory
  localRoot: string
  // Root directory of the node
  remoteRoot: string
  // Try to automatically skip code that is not mapped to the source file
  smartStep: boolean
  // Automatically skip these glob files
  skipFiles: array
  // Whether to enable diagnostic output
  trace: boolean
  presentation: {
    // Whether to hide, true means to hide invisible default false
  	hidden: boolean,
    // The smaller the sort number, the more first
    order: number,
    // the group name is the same as the group name
    group: string
  }
}
interface launch {
  // The absolute path to the Node.js program to debug
  program: string
  // Parameters passed to program debugging
  args: array
  // Start the program in this directory for debugging
  cwd: '${workspaceFolder}'
  // The absolute path to the runtime executable to use. The default is the node
  runtimeExecutable: 'node' | 'npm' | string
  // Optional arguments passed to the Runtime executable
  runtimeArgs: string
  // Select a specific version of Node.js
  runtimeVersion: string
  // This property expects environment variables as a list of key/value pairs of string type
  env: {}
  // The optional path to the file containing the environment variable definition
  envFile: '${workspaceFolder}/.env'
  // Start the program console
  console: 'internalConsole' | 'integratedTerminal' | 'externalTerminal'
  outputCapture: string
}
interface attach {
  // When using the processId attribute, the debug port is automatically determined based on node.js version (and protocol used) and cannot be explicitly configured. So do not specify the port attribute.
  processId: string
}
Copy the code

3. Platform specific properties

Json supports different property values for different operating systems. Args uploads values on Windows, stopOnEntry uploads values on MacOS

{
  "version": "0.2.0"."configurations": [{"type": "node"."request": "launch"."name": "Launch Program"."program": "${workspaceFolder}/node_modules/gulp/bin/gulpfile.js"."args": ["myFolder/path/app.js"]."windows": {
        "args": ["myFolder\\path\\app.js"]},"stopOnEntry": true."osx": {
        "stopOnEntry": false}}}]Copy the code
  • Windowswindows
  • Linuxlinux
  • MacOSosx

4. Launch vs Attach

Launch refers to attaching debug sessions to the next node debugger that is launched directly (i.e. -inspect-brk =port). Attach means to attach debug sessions to the port of the specified running node program in Debug mode. If the node program is not in Debug mode, provide processId.

5. Source Maps

Source Maps is enabled by default. If the compiled file is not in the same directory, you need to set outFiles attribute to tell debug where the source adpater file is.

6. Variable substitution

Paths and other values commonly used by VSCode can be used as variables.

{
  "type": "node"."request": "launch"."name": "Launch Program"."program": "${workspaceFolder}/app.js"."cwd": "${workspaceFolder}"."args": ["${env:USERNAME}"]}Copy the code

4, variables,

1. List of variables

  • ${workspaceFolder}– inVS CodeThe path to the folder opened in
  • ${workspaceFolderBasename}– inVS CodeThe name of the folder opened in, without a slash (/);
  • ${file}– Current open file;
  • ${fileWorkspaceFolder}– Workspace folder of the currently open file;
  • ${relativeFile}– relative to theworkspaceFolderThe currently open file;
  • ${relativeFileDirname}– The directory name of the currently open file;
  • ${fileBasename}– Of the currently open filebasename;
  • ${fileBasenameNoExtension}– Of the currently open filebasename, no file extension;
  • ${fileDirname}– Of the currently open filedirname;
  • ${fileExtname}– Extension of the current open file;
  • ${cwd}– The current working directory of the task running program at startup;
  • ${lineNumber}– The currently selected line number of the selected file;
  • ${selectedText}– The currently selected text in the selected file;
  • ${execPath}VS CodeThe running path of the executable file;
  • ${env:Name}-Environment variables;
  • ${config:Name}– Configure variables;
  • ${command:commandID}commandVariables;
  • ${defaultBuildTask}– Name of the default build task;
  • ${pathSeparator}– Character used to separate components in file paths;
  • ${input:variableID}inputInput variables.

Example 2.

Suppose you have the following requirements:

  1. Located in the/home/your-username/your-project/folder/file.extFiles opened in the editor;
  2. The directory/home/your-username/your-projectOpens as the root workspace.

Therefore, you will have the following values for each variable:

  • ${workspaceFolder}/home/your-username/your-project
  • ${workspaceFolderBasename}your-project
  • ${file}/home/your-username/your-project/folder/file.ext
  • ${fileWorkspaceFolder}/home/your-username/your-project
  • ${relativeFile}folder/file.ext
  • ${relativeFileDirname}folder
  • ${fileBasename}file.ext
  • ${fileBasenameNoExtension}file
  • ${fileDirname}/home/your-username/your-project/folder
  • ${fileExtname}.ext
  • ${lineNumber}– The line number of the cursor
  • ${selectedText}– Selected text in the code editor
  • ${execPath}Code.exeThe location of the
  • ${pathSeparator}– inmacOSlinuxfor/In theWindowsupper\

3. Variables within the scope of each Workspace folder

You can access the peer root folder of your workspace by appending the name of the root folder to a variable (separated by a colon). If there is no root folder name, the scope of the variable is the same as the folder in which it is used. For example, in Client in a multi-root workspace with folders Server and, ${workspaceFolder:Client} refers to the path to the Client root.

4. Environment variables

You can also reference environment variables through the ${env:Name} syntax (for example, ${env:USERNAME}).

{   
  "type": "node"."request": "launch"."name": "Launch Program"."program": "${workspaceFolder}/app.js"."cwd": "${workspaceFolder}"."args": ["${env:USERNAME}"]}Copy the code

5. Configvariable

${config:Name} ${config:editor.fontSize}

6. Commandvariable

${command:commandID}

{
  "configurations": [{"type": "node"."request": "attach"."name": "Attach by Process ID"."processId": "${command:extension.pickNodeProcess}"}}]Copy the code

7. Inputvariable

${input:variableID}

{
  "version": "2.0.0"."tasks": [{"label": "task name"."command": "${input:variableID}"
      // ...}]."inputs": [{"id": "variableID"."type": "type of input variable"
      // type specific configuration attributes}}]Copy the code

Currently VS Code supports three types of input variables:

  1. promptString: Displays an input box to get a string from the user.
  2. pickString: Displays a quick selection drop-down menu that allows the user to select from multiple options.
  3. command: Runs any command.
  • PromptString:
    1. description: displays in quick input to provide context for input.
    2. default: The default value will be used if the user enters no other content.
    3. password: set totrueEnter with a password prompt that does not display the typed value.
  • PickString:
    1. description: appears in quick selection to provide context for input.
    2. options: An array of options for the user to select.
    3. default: The default value will be used if the user enters no other content. It must be one of the option values.
  • Command:
    1. command: command to run on variable interpolation.
    2. args: Optional options package passed to the command implementation.
{
  "version": "2.0.0"."tasks": [{"label": "ng g"."type": "shell"."command": "ng"."args": ["g"."${input:componentType}"."${input:componentName}"]}],"inputs": [{"type": "pickString"."id": "componentType"."description": "What type of component do you want to create?"."options": [
        "component"."directive"."pipe"."service"."class"."guard"."interface"."enum"."enum"]."default": "component"
    },
    {
      "type": "promptString"."id": "componentName"."description": "Name your component."."default": "my-new-component"}}]Copy the code

5. Composite configuration

Compound launch configurations

1. Add the configuration

2. Select the required configuration

Second,Contributes BreakpointsDebugger breakpoint

The extension lists the language file types that will enable setting breakpoints.

{
  "contributes": {
    "breakpoints": [{"language": "javascript"
      },
      {
        "language": "javascriptreact"}}}]Copy the code

Three,Contributes Debuggers

1. The attribute

● Type is the unique ID used to identify the debugger in the launch configuration, consistent with type in the launch.json configuration. ● Label is the name of the debugger in VS Code. ● Path to program debug adapter that implements VS Code debug protocol for the actual debugger or runtime. ● Runtime If the path to the debug adapter is not an executable, but runtime is required. ● configurationAttributes is the architecture of the startup configuration parameters specific to this debugger. Note that the JSON schema constructs $ref and definition is not supported. ● initialConfigurations are used to populate the launch configuration of the initial launch.json. ● configurationSnippets can be launched through the configuration used by IntelliSense when editing launch.json. ● Variables introduces replacement variables and binds them to commands implemented by debugger extensions. ● languages Languages in which debugging extensions can be thought of as the “default debugger”.

Example 2.

{
  "contributes": {
    "debuggers": [{"type": "node"."label": "Node Debug"."program": "./out/node/nodeDebug.js"."runtime": "node"."languages": ["javascript"."typescript"."javascriptreact"."typescriptreact"]."configurationAttributes": {
          "launch": {
            "required": ["program"]."properties": {
              "program": {
                "type": "string"."description": "The program to debug."}}}},"initialConfigurations": [{"type": "node"."request": "launch"."name": "Launch Program"."program": "${workspaceFolder}/app.js"}]."configurationSnippets": [{"label": "Node.js: Attach Configuration"."description": "A new configuration for attaching to a running node program."."body": {
              "type": "node"."request": "attach"."name": "${2:Attach to Port}"."port": 9229}}]."variables": {
          "PickProcess": "extension.node-debug.pickNodeProcess"}}]}}Copy the code

Four,VSCode Debug API

1. The variable

1. activeDebugConsole: DebugConsole

The currently active debug console. If there is no active debug session, output sent to the debug console is not displayed.

2. activeDebugSession: DebugSession | undefined

Debug session that is currently active. If no debug session is activated, the value is undefined.

3. breakpoints: readonly Breakpoint[]

Breakpoint list

2. The event

1. onDidChangeActiveDebugSession: Event<DebugSession | undefined>

An event that fires when the active debug session changes, and also when the active debug session changes to undefined.

2. onDidChangeBreakpoints: Event<BreakpointsChangeEvent>

Events that are triggered when a breakpoint set is added, deleted, or changed.

3. onDidReceiveDebugSessionCustomEvent: Event<DebugSessionCustomEvent>

The event that fires when a custom DAP event is received from a debug session.

4. onDidStartDebugSession: Event<DebugSession>

Events that are triggered when a new debug session is started.

5. onDidTerminateDebugSession: Event<DebugSession>

Events that are triggered when a debug session terminates.

Method 3.

1. addBreakpoints(breakpoints: readonly Breakpoint[]): void

Add a breakpoint

parameter describe
breakpoints: readonly Breakpoint[] Added breakpoint

2. asDebugSourceUri(source: DebugProtocolSource, session? : DebugSession): Uri

Converts a source descriptor object received through the Debug Adapter Protocol into a Uri that can be used to load its content.

parameter describe
source: DebugProtocolSource Conforms to those defined in the debug adapter protocolSourceObject of type.
session? : DebugSession Optional debug session.
The return value
Uri One that can be used to load source contenturi.

3. registerDebugAdapterDescriptorFactory(debugType: string, factory: DebugAdapterDescriptorFactory): Disposable

Registers a debug adapter descriptor function for a specific debug type. Extension is only allowed to register a DebugAdapterDescriptorFactory extension defined debugging type. Otherwise an error will be thrown. For debugging type register multiple DebugAdapterDescriptorFactory can lead to errors.

parameter describe
debugType: string Registers the debug type of the function.
factory: DebugAdapterDescriptorFactory The function to register.
The return value
Disposable

4. registerDebugAdapterTrackerFactory(debugType: string, factory: DebugAdapterTrackerFactory): Disposable

Registers a debug adapter tracer function for the given debug type.

parameter describe
debugType: string Registers the debug type of the function.
factory: DebugAdapterTrackerFactory The function to register.
The return value
Disposable

5. registerDebugConfigurationProvider(debugType: string, provider: DebugConfigurationProvider, triggerKind? : DebugConfigurationProviderTriggerKind): Disposable

Register a Debug Configuration Provider for a specific debug type.

parameter describe
debugType: string Debug type.
provider: DebugConfigurationProvider registereddebug configuration provider
triggerKind? : DebugConfigurationProviderTriggerKind
The return value
Disposable

6. removeBreakpoints(breakpoints: readonly Breakpoint[]): void

Remove breakpoints

parameter describe
breakpoints: readonly Breakpoint[] Deleted breakpoints

7. startDebugging(folder: WorkspaceFolder | undefined, nameOrConfiguration: string | DebugConfiguration, parentSessionOrOptions? : DebugSession | DebugSessionOptions): Thenable<boolean>

Start debugging by using named startup or named composite configuration or by passing DebugConfiguration directly.

parameter describe
`folder: WorkspaceFolder undefined`
`nameOrConfiguration: string DebugConfiguration`
`parentSessionOrOptions? : DebugSession DebugSessionOptions`
The return value
Thenable<boolean>

8. stopDebugging(session? : DebugSession): Thenable<void>

Stops the given debugging session, or all debugging sessions if omitted.

parameter describe
session? : DebugSession Debug session
The return value
Thenable<boolean>

Five,Debugging ArchitectureDebugging architecture

1. Debug Adapter

VS CodeImplements a general-purpose (language independent) debuggerUIIt is based on an abstract protocol. Because debuggers typically do not implement this protocol, some mediation is needed to “tune” the debugger to the protocol. This mediation is usually a separate process that communicates with the debugger.We call this mediation a debug adapter for shortDA.Debug Adapter),DAVS CodeThe abstract protocol used is the Debug adapter protocol (abbreviatedDAP.Debug Adapter Protocol). Because the debug adapter protocol is independentVS CodeYes, it has its ownWeb site.

Because debug adapters are independent of VS Code and can be used in other development tools, they do not match VS Code’s extensibility architecture based on extensions and contribution points.

For this reason, VS Code provides a contribution point where debuggers, debug adapters, can contribute under a particular debug type (such as Node for the Node.js debugger). When the user starts this type of debug session, VS Code starts the registered DA.

Thus, in its most basic form, a debugger extension is just a declarative contribution to the debug adapter implementation, while an extension is basically a package for the debug adapter without any additional code.

2. Demo

Vscode-mock-debug github address: github.com/Microsoft/v…

1. cloneCome down,yarnThe installationnode_modules

2. Open the folderpackage.jsonfile

The file is configuredbreakpointsdebuggersTwo parameters. With the above attribute parsing we know that this plug-in sets the language type tomarkdowntypeA value ofmockOne of thedebuggers

3. F5Launch the plug-in or click on the leftDebugbutton

You can seelaunch.jsonConfiguration in the file.

4. Click leftDebugbutton

You can see up hereselectThere’s one in the boxDebug readme.md, and then start to seemarkdownThe file is under debugging.

5. Close what you just openedvs codeGo back tocloneThe project,breakpointsdebuggersTo add the new configuration.

debuggersconfigurationmockJsJust follow the abovemockThe configuration is copied and then modifiedtypeconfigurationSnippetslabelCan. The configuration is as follows:

{
	"type": "mockJs"."languages": ["javascript"]."label": "Mock Debug Js"."program": "./out/debugAdapter.js"."runtime": "node"."configurationAttributes": {
	  "launch": {
	    "required": [
	      "program"]."properties": {
	      "program": {
	        "type": "string"."description": "Absolute path to a text file."."default": "${workspaceFolder}/${command:AskForProgramName}"
	      },
	      "stopOnEntry": {
	        "type": "boolean"."description": "Automatically stop after launch."."default": true
	      },
	      "trace": {
	        "type": "boolean"."description": "Enable logging of the Debug Adapter Protocol."."default": true
	      },
	      "compileError": {
	        "type": "string"."description": "Simulates a compile error in 'launch' request."."enum": [
	          "default"."show"."hide"]."enumDescriptions": [
	          "default: show fake compile error to user"."show fake compile error to user"."do not show fake compile error to user"}}}},"initialConfigurations": [{"type": "mockJs"."request": "launch"."name": "Ask for file name"."program": "${workspaceFolder}/${command:AskForProgramName}"."stopOnEntry": true}]."configurationSnippets": [{"label": "Mock Debug Js: Launch"."description": "A new configuration for 'debugging' a user selected js file."."body": {
	      "type": "mockJs"."request": "launch"."name": "Ask for file name"."program": "^\"\\${workspaceFolder}/\\${command:AskForProgramName}\""."stopOnEntry": true}}]."variables": {
	  "AskForProgramName": "extension.mock-debug.getProgramName"}}Copy the code

6. After the configuration, clicksampleWorkspaceCreate in folderindex.jsFile, write code.

7. Click on the leftDebugButton, selectExtension + ServerOption and start debugging

8. In the newly opened windowlaunch.jsonFile, clickAdd Configuration...Button, selectMock Debug Js: Launch

And modify the configuration

{
	"type": "mockJs"."request": "launch"."name": "Debug js"."program": "${workspaceFolder}/index.js"."stopOnEntry": true
}
Copy the code

9. Click on theDebugButton, selectDebug jsoptions

You can debugjsfile