Debugging Figma Plugins in VS Code
Tags: vscode, tutorial, productivity, devto
Published: 2023-01-08 19:52:22

Figma is a powerful design tool that allows developers to create custom plugins for it. However, developing these plugins can be difficult, especially if you need to debug your code to understand what's going on.

One recommended method for debugging Figma plugins is to use Chrome Dev Tools. However, some people find the interface of Dev Tools to be cluttered, and it can be inconvenient to switch between multiple windows unless you have a multi-monitor setup.

In this post, I'll show you how to set up Visual Studio Code for debugging your Figma plugins. I'll also provide some tips to make your debugging experience more pleasant.

## TL;DR - Summary of the Steps
  
1. Enable source map generation in your build tool of choice (e.g. TypeScript, Babel, Webpack, Esbuild, Vite)

2. Add the necessary configurations to your launch.json file:
   - Run Figma with the necessary flags for remote debugging and inspection
   - Attach a Chrome debugger to a Figma process

3. Configure a task in the tasks.json file to make Visual Studio Code wait after launching Figma before trying to attach to it

4. Open your test file in Figma and enable the "Use developer VM" option in the "Plugins > Development" menu

5. Quit Figma without closing the test file tab

6. Run the compound task "Run and Attach to Figma" in Visual Studio Code

## Generating Source Maps

A source map is a file that maps the code in a compiled file (such as a minified JavaScript file) back to the original source code. This can be useful when debugging, as it allows you to see the original source code and set breakpoints in it, rather than debugging the compiled code.

To enable source map generation in TypeScript, you can update your `tsconfig.json` file as follows:

```json
{
  "compilerOptions": {
    ...
    "sourceMap": true
  }
}
```

You can also enable source maps in other build tools, such as Babel, Webpack, Esbuild, or Vite. A quick Google search will find tutorials on how to enable source maps in your bundler of choice, but I've saved you the trouble and added several links at the end of this article.

Once you have enabled source map generation, you should be able to see the original source code and set breakpoints in it when debugging in Visual Studio Code.


## Configuring Visual Studio Code

To set up Visual Studio Code for debugging Figma plugins, we'll need to edit the `launch.json` and `tasks.json` files.

First, we'll add a launch configuration to launch.json to run Figma with the necessary flags for remote debugging and inspection.

> **<u>NOTE:</u>** You'll need to update `"runtimeExecutable"` if are using Windows

```json
{
  "name": "Run Figma",
  "type": "node",
  "request": "launch",
  "cwd": "${workspaceFolder}",
  "internalConsoleOptions": "neverOpen",
  "runtimeExecutable": "/Applications/Figma.app/Contents/MacOS/Figma",
  "runtimeArgs": [
    "--args",
    "--remote-debugging-port=9222",
    "--inspect",
    "--log-level=2",
    "-v=2"
  ],
  "outputCapture": "std",
  "autoAttachChildProcesses": true,
  "console": "integratedTerminal",
  "presentation": {
    "hidden": false,
    "group": "Figma",
    "order": 1
  }
}
```

The configuration above runs Figma with the `--remote-debugging-port=9222` and `--inspect` flags, to enable remote debugging and inspection.
The `--log-level` and `-v` flags enable verbose logging, which can also be helpful when debugging.

Next, we'll configure a task to make Visual Studio Code wait after launching Figma. You can do that in `.vscode/tasks.json`:

```jsonc
{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Wait for it",
      "detail": "Sleep for 10 seconds",
      "type": "shell",
      "command": "sleep 10",
      "isBackground": false,
      "windows": {
        "command": "ping 127.0.0.1 -n 10 > nul"
      },
      "runOptions": {
        "instanceLimit": 1,
      },
      "promptOnClose": false,
      "hide": false,
      "presentation": {

        "reveal": "never",
        "panel": "dedicated",
        "showReuseMessage": false,
        "close": true,
        "echo": false
      },
      "problemMatcher": []
    }
  ]
}
```

Back to `launch.json` we can now create a configuration that will wait for Figma to launch and show you a show a menu for you to pick the correct tab VS Code should attach the debugger to.

Then we can add a `compound` configuration to run everything in sequence when we press `F5` \o/

Here's the full `launch.json` file:

```jsonc
// For more information, visit:
// https://go.microsoft.com/fwlink/?linkid=830387
{
  "version": "0.2.0",
  "compounds": [
    {
      "name": "Run Figma then Attach",
      "configurations": ["Run Figma", "Wait to Attach to Figma"],
      "stopAll": false,
      "presentation": {
        "hidden": false,
        // __ will place this at the top of the debug menu
        "group": "__",
        "order": 1
      }
    }
  ],
  "configurations": [
    {
      "name": "Run Figma",
      "type": "node",
      "request": "launch",
      "cwd": "${workspaceFolder}",
      "internalConsoleOptions": "neverOpen",
      "runtimeExecutable": "/Applications/Figma.app/Contents/MacOS/Figma",
      "runtimeArgs": [
        "--args",
        "--remote-debugging-port=9222",
        "--inspect",
        "--log-level=2",
        "-v=2"
      ],
      "outputCapture": "std",
      "autoAttachChildProcesses": true,
      "console": "integratedTerminal",
      "presentation": {
        "hidden": false,
        "group": "Figma",
        "order": 1
      }
    },
    {
      "preLaunchTask": "Wait for it",
      "name": "Wait to Attach to Figma",
      "type": "chrome",
      "request": "attach",
      "address": "localhost",
      "port": 9222,
      "targetSelection": "pick",
      "pauseForSourceMap": true,
      "pathMapping": {
        "/file/": "${workspaceRoot}/",
        "../src/": "${workspaceRoot}/src/",
        "src/": "${workspaceRoot}/src/"
      },
      "outFiles": [
        "${workspaceFolder}/build/*.js",
        "${workspaceFolder}/build/*.js.map",
      ],
      "presentation": {
        "hidden": true,
        "group": "Figma",
        "order": 2,
      },
      "internalConsoleOptions": "openOnSessionStart"
    },
    {
      "name": "Attach to Figma",
      "type": "chrome",
      "request": "attach",
      "address": "localhost",
      "port": 9222,
      "targetSelection": "pick",
      "pauseForSourceMap": true,
      "pathMapping": {
        "/file/": "${workspaceRoot}/",
        "../src/": "${workspaceRoot}/src/",
        "src/": "${workspaceRoot}/src/"
      },
      "outFiles": [
        "${workspaceFolder}/build/*.js",
        "${workspaceFolder}/build/*.js.map",
      ],
      "presentation": {
        "hidden": false,
        "group": "Figma",
        "order": 2,
      },
      "internalConsoleOptions": "openOnSessionStart",
    },
  ]
}
```

## Preparing the Figma App

Before you start having fun debugging your awesome plugin, I recommend you get Figma to the right "state".

So open up Figma and let's 2 two things...

### 1. Open your test file

You probably have a test file, right? So it's good to have Figma automatically open it when ran so we can pick its tab from VS Code.

**Remember to quit Figma WITHOUT closing that tab!**

### 2. Enabling the Developer VM

You probably already know, since the desktop app is required to develop plugins,  but this option is only available in Figma's desktop app (not the web app).

When the option is enabled, the plugin code runs in the browser's JavaScript engine, so that developer tools can be used.

When enabled, you'll Figma will remember this choice and, by having it enabled, VS Code will start loading source maps the first time you run the plugin.

> **<u>NOTE:</u>** There's currently an issue in Figma regarding plugin titles. If you customize your plugin window title, Figma will **NOT** display "(Developer VM)" text after it

Here's where you enable it:

![Image shows a mouse pointer hovering the menu option at Plugin, Development, "Use Developer VM" selected](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/60upm1q7xselbj9z1im7.png)

## At last the rewards!

Here's the Debug Console after you've attached your IDE to the Figma process:

![Image shows a screenshot of the Debug Console panel of VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/30rn2qv21plnli2ki0f2.png)


## Key Takeaways

Source maps are like the Holy Grail of debugging any compiled or minified code (I'm using TypeScript). Without them, you're basically navigating a maze blindfolded. Setting up all this for debugging of in Visual Studio Code looks like a lot work... but figuring this
all out was way worse and after a week on this setup I think it was really worth it.

Trust me, the extra work you'll put in now will be well compensated in the long run.

**A couple notes on the experience so far**

- Figma randomly crashes during debug sessions, but some actions make it especially unhappy:
  - Trying to call `figma.` anything, really
    Solution: move those calls behind a service and never step into that file

  - Trying to add variables to the watch panel (even when you are using Chrome Dev Tools)

- If you pay attention to the image above you'll notice there are some mumbled log messages there
  I've filed an [issue regarding those on vscode-js-debug](https://github.com/microsoft/vscode-js-debug/issues/1511)
  In the meantime, if you have too many messages you may want to stick with dev tools

- I **strongly** recommend using the [debug package](https://www.npmjs.com/package/debug) from NPM to organize your log messages

## Relevant Resources

- [Figma's documentation on plugin development](https://www.figma.com/plugin-docs/)

- [Visual Studio Code's documentation on debugging](https://code.visualstudio.com/docs/editor/debugging)

- [Babel source map options](https://babeljs.io/docs/en/options#source-map-options)

- [Webpack `devtool` (source maps)](https://webpack.js.org/configuration/devtool/)

- [Esbuild source maps](https://esbuild.github.io/api/#sourcemap)

- [Vite `build.sourcemap` option](https://vitejs.dev/config/build-options.html#build-sourcemap)