# Javascript Debugging

A good interactive debugger is essential for any non-trivial software project. PinballY doesn't have its own built-in debugger window, but it has something better: it lets you connect a real debugger. It currently works with the following:

- Visual Studio Code, Microsoft's free, open-source code editor and Javascript IDE
- Chrome DevTools, the debugger console built in to the Chrome browser

Debugging is handled through the Chrome DevTools protocol. This is a standard protocol that's implemented by most Windows Javascript debuggers and IDEs, so in principle, you should be able to use any debugger that implements the protocol. However, be warned that the protocol implementation in ChakraCore is extremely immature and incomplete. Microsoft is building the debugger interface as a separate project from the main ChakraCore engine, and so far they're really only at the prototype stage. They're also only thinking in terms of VS Code support, so support for other debuggers (like Chrome) is an afterthought at best. Fortunately, they've made it open-source (like Chakra Core itself), so I've been able to flesh it out enough to make it fairly usable with VS Code and the Chrome debugger. You might be able to get it working with other Javascript debuggers, if there's something else you prefer, but it might be a bit shaky.

If you run into any problems with debugging, feel free to report them as issues, but be aware that it might not be practical for me to add any substantial missing features until Microsoft makes more progress on this. Hopefully they'll continue developing it and it'll become more complete over time.

## Simple instrumentation

For very simple debugging tasks, you can sometimes get enough information by instrumenting your code with debugging messages. One way to do that is to display messages through the user interface, such as via the message() function. Another way that's less intrusive in the UI is to use logfile.log(), which writes messages to the log file for review after the session ends.

## Pausing in the debugger

One of the main functions of any debugger is the ability to pause execution at any arbitrary point in the program, so that you can inspect the current values of all variables and step through sections of code one line at a time. The exact command to pause execution varies by debugger, but the VS Code and the Chrome debugger have similar UI features, with buttons to pause execution of the running program, step one line at a time, and set breakpoints at source locations.

At program startup, the debugger will normally pause execution at the first line of your main.js script. You can override the initial stop location using the /jsdebug:break=xxx command-line option when starting PinballY.

VS Code and Chrome both have "pause" buttons, which cause the debugger to interrupt the Javascript program at the next opportunity while it's running. The debugger can only break into Javascript code, so pressing the button won't have any effect until the next Javascript script executes, which will happen the next time one of your event handlers fires. The pause button thus might not do anything immediately, since it won't interrupt execution until something is happening in Javascript.

Whenever execution is paused in the debugger, be aware that PinballY's windows won't respond to mouse clicks or keyboard input. That's because your Javascript scripting code is effectively part of the PinballY's user interface code. Freezing Javascript execution therefore also freezes the PinballY user interface. When you resume execution from the debugger, the PinballY windows will return to normal.

## Visual Studio Code setup

VS Code is Microsoft's free and open-source code editor, which can also serve as a fairly full-featured IDE for Javascript. If you don't already have a good code editor, you might try VS Code as a combined editor and debugging environment.

Full documentation for VS Code is available on the VS Code docs site.

Note that you don't have to install the traditional Visual Studio (Microsoft's large-scale IDE for system programming languages like C++ and C#) to use VS Code. VS Code is a completely independent, standalone program that doesn't depend upon Visual Studio in any way, despite the similar name.

Here's the full setup procedure, starting from scratch. If you already have VS Code installed, just skip the download-and-install step.

- Download Visual Studio Code from Microsoft and run the installer
  - What if I already have Visual Studio installed? That makes no difference. It's a completely unrelated program. You still have to install VS Code separately.
- Launch Visual Studio Code
- On the menu, select File > Open Folder
- That'll bring up a folder selection dialog; navigate to your PinballY > Scripts folder and click Select Folder
- On the main menu again, select Debug > Add Configuration, then select Node.js from the popup menu. That should open a file called launch.json that looks something like this:
  { "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Launch Program", "program": "${file}" } ] }
- Replace all of that with the text below:
  { "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "PinballY", "runtimeExecutable": "${workspaceFolder}/../PinballY.exe", "runtimeArgs": ["/jsdebug:port=9228"], "port": 9228, "protocol": "inspector", "stopOnEntry": true } ] }
- If you want to use a different TCP port number (see Choosing a port number), substitute it for the default 9228 shown above (note that it appears twice, once in the "runtimeArgs" line and once in the "port" line; both must always agree)
- Save changes

VS Code will now be set up to connect to PinballY. You can return to this configuration in future sessions by using File > Select Folder to return to the same PinballY Scripts folder, since VS Code keeps its configuration data with the folder.

You can go back and manually edit that launch.json file at any time, or create it manually yourself. You'll find it in the .vscode folder within your PinballY Scripts folder (or whichever folder you selected in the "navigate to your Scripts folder" step above).

### Starting a debug session with VS Code

This procedure launches PinballY as a child process of the VS Code debugger, so you should close any running instance of PinballY first.

- Open VS Code
- If your PinballY project folder isn't already open, use File > Open Folder to navigate back to your PinballY Scripts folder
- Select View > Debug
- At the top of the left panel, make sure the Debug drop list is set to PinballY. If it's not, select that from the drop list.
- Click the big green arrow next to PinballY, or press F5 ("Go"), or select Debug > Start Debugging

PinballY will now launch, and the debugger will take control as soon as the first Javascript code starts running. You can now set breakpoints for any code you want to step through, or do any other initial setup for the debugging session. Press F5 to continue execution.

### Launching PinballY and VS Code separately

You'll probably find it most convenient to launch PinballY directly from VS Code as described above, but there's another way to do it. You can alternatively launch PinballY yourself, and then "attach" VS Code later.

- In your launch.json file, change the line that says "request":"launch" to read "request":"attach" instead. That setting in VS Code makes the debugger connect to an existing process rather than trying to launch a child process.
- Launch PinballY, manually entering the desired /jsdebug command line options. You can do that by creating a Windows desktop shortcut that includes the options, or by typing the whole command line into the Windows desktop "Run" box (press Windows+R).
- After PinballY has started, go back to VS Code, go to View > Debug, and select the modified "attach" configuration in the drop list at the top of the debugger panel
- Click the big green arrow or press F5 to start debugging
- VS Code will attach to your already-running PinballY session, so you can proceed with debugging activities as normal

## Chrome DevTools setup

The Chrome DevTools are built in to the Google Chrome browser, so if you have Chrome installed, you already have a nice Javascript debugger installed. The Chrome debugger is more of a standalone debugger than a full IDE like VS Code, so you might prefer VS Code if you want a more integrated user interface. Also note that VS Code support is Microsoft's first (and really only) priority, so Chrome support might lag in some ways.

The launching procedure with the Chrome debugger is a little different from VS Code. Chrome won't launch PinballY for you the way that VS Code does. Instead, you have to launch each program (Chrome and PinballY) separately, and then tell Chrome to connect to the running PinballY instance. PinballY accommodates this by pausing in a "Waiting for debugger" dialog until a debugger connects, giving you a chance to intercept the startup scripts without any super-human feats of timing.

Here's the setup procedure:

- If you don't already have Google Chrome installed, download it and install it. You just need the ordinary Chrome browser - the debugger is built in to every copy of Chrome.
- Open the Chrome browser
- In the address bar, type chrome://inspect and press return
- Click the Devices tab in the list on the left (usually unnecessary, as this tab should come up by default)
- Make sure the "Discover network targets" checkbox is ticked (it should be by default)
- Click the "Configure..." button next to "Discover network targets"
- Add localhost:9228 to the port list (or substitute the port number of your choice: see Choosing a port number)
- Click Done
- Start PinballY, using the /jsdebug option as described in /jsdebug option.
- Once PinballY starts up, the Chrome window will show a new PinballY entry under the Remote Target list. Click its inspect link.
- This will open a new window showing the DevTools debugger interface. You can now set breakpoints, step through code, and perform other debugging tasks.

## Generic setup for other tools

Warning: As mentioned earlier, ChakraCore's debugger interface is only designed to work with VS Code. It might work in a limited way with other debuggers that implement the Chrome DevTools protocol, but many functions are likely to be broken. Even so, I'm documenting the basic setup procedure here for reference, in the hope that support for other tools improves in the future.

If you want to try an alternative debugger, here's the generic setup procedure. You'll have to adapt the steps to your debugger's particular settings dialogs or configuration file setup, of course.

- Start PinballY with Javascript debugging enabled, using the /jsdebug command-line option
- Run the debugger or IDE as a separate process
- The debugger connects to PinballY via a numbered TCP port (local network port)
- The port number is up to you (see Choosing a port)
- You have to configure both PinballY and your debugger/IDE to use the port number you chose
- You initiate the debugging session by telling your debugger/IDE to connect to the selected port, after PinballY has started

Startup procedure: By default, when you use /jsdebug to start PinballY in Javascript debugging mode, PinballY waits for a debugger to connect before doing anything else. As soon as the debugger connects, PinballY loads its own built-in Javascript code, then stops in the debugger just before the first line of your main.js script is executed. This gives you a chance to step through your script code from the beginning if you want to. You can simply use your debugger's "Go" or "Continue" command if you don't need to step through your startup code.

### Choosing a port number

The "port number" we've referred to a number of times is a local TCP port number. This is a type of network port, but in this case it doesn't actually access your LAN or Internet connection; it's just for local connections between programs running on your computer. The port number simply identifies the port so that the applications can connect to each other.

Any port from 1024 to 49151 is valid, as long as the port isn't already in use by some other program. The default port is 9228, which isn't used by any common software that I know of. PinballY will show an error at startup if you choose a port that's already in use; if you see such an error, simply choose a different number in the valid range.

The range of valid ports is so large that it's usually easy to find a free port by just choosing one randomly. However, if you want to see a list of exactly which ports are in use on your computer, type netstat /an into a CMD prompt window. Look for entries in the "Local address" column with address 127.0.0.1: the number after the ":" is the port number.

How to tell PinballY which port to use: On the PinballY command line, enter the port number like this (substituting the port number of your choice for the default 9228):

PinballY.exe /jsdebug:port=9228

How to tell your debugger which port to use: That's different for each debugger. For VS Code, you enter it in the launch.json file under the "port" setting. For Chrome, you add it to the "network targets" list as localhost:port.

## /jsdebug option syntax

The /jsdebug command-line option tells PinballY to enable Javascript debugging. Debugging is disabled by default, since it adds a little bit of performance overhead.

/jsdebug by itself enables debugging and selects a number of default settings. You can change the defaults by adding some extra sub-options to the /jsdebug parameter. Append sub-options to /jsdebug after a colon (":"). To use more than one sub-option, separate them with commas:

PinballY.exe /jsdebug:port=9228,break=system

The sub-options are:

- port=portNumber: Sets the TCP port number for the connection between the VS Code debugger and PinballY's Javascript engine. The default is port 9228, but any assignable TCP port (1024 to 49151) can be used. You can change this to a different port if you have some other software on your system that's already using this port. This is a TCP port, so it's network-related, but it's not really a network port; it's on "localhost", which means that it's only for connections within the same machine, and doesn't connect to anything outside via your LAN or Internet.
- break=where: Sets the initial "break" position where the debugger takes control and pauses the Javascript program. This can be one of the following:
  - break=user: This is the default. The debugger will initially stop at the first line or your main.js script, skipping the boilerplate system setup code that PinballY executes before loading your script.
  - break=system: The debugger will pause initially at the first line of the boilerplate system code that PinballY executes on startup. You can use this if you want to look at what the system code is doing out of curiosity or because you want to debug something going wrong there.
  - break=none: The debugger won't initially pause at all. You can use this if you don't need to debug any of your startup code and want to control things manually via breakpoints or the "pause" button in the debugger UI.

    Tip: Visual Studio Code might be confused by break=none, because it normally expects the target engine to stop in the debugger at startup. After starting up with this option, VS Code might think it's paused in the debugger, even though the Javascript engine isn't actually paused. You can usually get things back in sync by clicking the "Go" button in VS Code. The more reliable fix is to change the "stopOnEntry:" setting in launch.json to false, to tell Code not to expect the initial break in the first place. If you do that, remember that you'll have to set it back to true if you change the /jsdebug options back to break=user or break=system.

- wait=yesOrNo: Tells PinballY whether or not it should wait for the debugger to establish its connection before proceeding to execute any Javascript code. The default is wait=yes. Waiting for the connection ensures that the debugger has a chance to restore saved breakpoints, and lets you step through your startup code if desired. wait=no tells the program to set up the debugger interface, but doesn't wait for a debugger to connect. Startup Javascript code is executed without trying to pause in the debugger. This gives you the option to connect a debugger later, but allows the program to run freely without a debugger until you connect one.