Skip to content

[ xdebug ] Bridge DBGP session with CDP server #2402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jul 23, 2025
Merged

Conversation

adamziel
Copy link
Collaborator

@adamziel adamziel commented Jul 22, 2025

Motivation for the change, related issues

Populates the new php-wasm-xdebug-bridge package which will connect Xdebug with Browser Devtools.

Roadmap

Related issues and pull requests

Implementation details

  • DBGP communication TCP server, which the bridge uses to communication between PHP.wasm XDebug and the CDP server. XDebug defaultly discusses on port 9003. While the DBGP server is set on port 9003 by default.

  • CDP Websocket Server, which communicates between the Browser Devtools and the DBGP server, with the help of a bridge. The default port is 9229.

  • XDebug <-> CDP Bridge, which ties the above implementations together. It plays with all the specificities of the DBGP protocol and the CDP protocol.

  • A startBridge function that will initialize the servers, get the soon-to-be-debugged files and return the built bridge.

  • A CLI tool that will start the bridge between the browser and a XDebug.

Testing Instructions

Create a xdebug.php PHP file at the root of the repository :

<?php

$test = 42;  // Set a breakpoint on this line

echo "Output!\n";

function test() {
	echo "Hello Xdebug World!\n";
}

test();

From Wordpress-Playground repository

  1. Run the xdebug-bridge command in a first terminal :
> npx nx run php-wasm-xdebug-bridge:dev

...

Chrome connected! Initializing Xdebug receiver...
XDebug receiver running on port 9003
Running a PHP script with Xdebug enabled...
  1. Run the php-wasm-cli command in a second terminal :
> nx run php-wasm-cli:dev --xdebug xdebug.php

Output!
Hello Xdebug World!

From non-related Playground project

  1. Install dependencies
npm install @php-wasm/cli @php-wasm/xdebug-bridge
  1. Run the xdebug-bridge command in a first terminal :
> npx xdebug-bridge

...

Chrome connected! Initializing Xdebug receiver...
XDebug receiver running on port 9003
Running a PHP script with Xdebug enabled...
  1. Run the @php-wasm/cli command in a second terminal :
> npx cli --xdebug xdebug.php

Output!
Hello Xdebug World!
screencapture

@mho22 mho22 mentioned this pull request Jul 22, 2025
12 tasks
@mho22
Copy link
Collaborator

mho22 commented Jul 22, 2025

I’d be happy to take over tomorrow morning, unless you get to it first!

@mho22 mho22 mentioned this pull request Jul 22, 2025
@mho22
Copy link
Collaborator

mho22 commented Jul 23, 2025

I implemented the build by having a look at the other packages, removing what was unnecessary and relying mainly on @wp-playground/cli since it has also two files to build. I may have made errors, don't hesitate to show them to me.

FYI, I am currently trying out the new package by running npm run local-package-repository. However, it crashes with this :

> npx xdebug-bridge

Starting XDebug Bridge...
file:///Users/mho/Work/Projects/Development/Web/Professional/xdebug/template/node_modules/@php-wasm/xdebug-bridge/cli.js:3012
    super(), this.ws = null, this.wss = new To.WebSocketServer({ port: t }), this.wss.on("connection", (e) => {
                                        ^

TypeError: To.WebSocketServer is not a constructor

While running nx run php-wasm-xdebug-bridge:dev from the current project successfully opens the devtools :

> npx nx run php-wasm-xdebug-bridge:dev

 NX   Resetting the Nx cache and stopping the daemon.



 NX   Successfully reset the Nx workspace.


> nx run php-wasm-xdebug-bridge:dev

> node --no-warnings --experimental-wasm-stack-switching --experimental-wasm-jspi --loader=./packages/meta/src/node-es-module-loader/loader.mts ./packages/php-wasm/xdebug-bridge/src/index.ts

Starting XDebug Bridge...
Connect Chrome DevTools to CDP at:
devtools://devtools/bundled/inspector.html?ws=localhost:9229

It seems to be linked with me changing target to es2020 instead of node20. I also added ws as an external dependency.

@mho22
Copy link
Collaborator

mho22 commented Jul 23, 2025

This video says it better than a long comment could :

output.mp4

You maybe noticed the xdebug-bridge binary with the php-root absolute path option. That is because I got a duplicate directory in the devtools without it. This is probably related to dbgp using absolute paths by default, at least, when I was using it with VSCode.

There is still two checks I want to do before I think we can review the changes :

  • log only when verbose enabled
  • if php-root is relative [ and it is by default ], then dbgp should be relative

I have to dig into this as I am not sure this being possible but, let's give it a try.

@mho22
Copy link
Collaborator

mho22 commented Jul 23, 2025

Focus on the xdebug-bridge tool inside the repository.

We need to run the following command :

> nx run php-wasm-xdebug-bridge:dev

Starting XDebug Bridge...
Connect Chrome DevTools to CDP at:
devtools://devtools/bundled/inspector.html?ws=localhost:9229

getPHPFiles was crashing on symlinks. Switching from statSync to lstatSync resolved the issue.

@mho22 mho22 changed the title XDebug <-> CDP bridge [ xdebug ] Bridge DBGP session with CDP server Jul 23, 2025
@mho22 mho22 force-pushed the port-xdebug-bridge branch from b6e4ab1 to ee31029 Compare July 23, 2025 14:45
@mho22 mho22 marked this pull request as ready for review July 23, 2025 16:27
@mho22 mho22 requested a review from a team as a code owner July 23, 2025 16:27
@adamziel
Copy link
Collaborator Author

Nice work @mho22!

@adamziel adamziel merged commit a875920 into trunk Jul 23, 2025
24 of 25 checks passed
@adamziel adamziel deleted the port-xdebug-bridge branch July 23, 2025 21:11
@mho22 mho22 added the XDebug label Jul 24, 2025
adamziel pushed a commit that referenced this pull request Jul 24, 2025
)

## Motivation for the change, related issues

This pull request adds a `--experimental-devtools` option in
`wp-playground/cli`.

[Roadmap](#2315)

## Related issues and pull requests

- #2408
- #2402
- #2398
- #2346
- #2288

## Implementation details

- Simple implementation of a Devtools option. It checks for a
`experimentalDevtools` argument that starts the `xdebug-to-cdp-bridge`
process.
- Changes the `StartBridgeConfig` `getPHPFile` property type from
`(path: string) => string` to `(path: string) => Promise<string>` and
adapt the related code.

## Testing Instructions

### In WordPress-Playground repository

1. Write a script like the following `cli.ts` : 

```typescript
import { runCLI } from "./packages/playground/cli/src/run-cli";

const script = `
<?php

$test = 42;

echo "Output!\n";

function test() {
	echo "Hello Xdebug World!\n";
}

test();
`;

const cliServer = await runCLI({command: 'server', xdebug: true, experimentalDevtools: true});

cliServer.playground.writeFile('xdebug.php', script);

const result = await cliServer.playground.run({scriptPath: `xdebug.php`});

console.log(result.text);
```

2. Run the following command : 

```
> node --no-warnings --experimental-wasm-stack-switching --experimental-wasm-jspi --loader=./packages/meta/src/node-es-module-loader/loader.mts cli.ts

Starting a PHP server...
Setting up WordPress undefined
Resolved WordPress release URL: https://downloads.w.org/release/wordpress-6.8.2.zip
Fetching SQLite integration plugin...
Booting WordPress...
Booted!
Running the Blueprint...
Running the Blueprint – 100%
Finished running the blueprint
WordPress is running on http://127.0.0.1:61290
Connect Chrome DevTools to CDP at:
devtools://devtools/bundled/inspector.html?ws=localhost:9229

...

Chrome connected! Initializing Xdebug receiver...
XDebug receiver running on port 9003
Running a PHP script with Xdebug enabled...
```

### In a non-related Playground project

1. Install dependencies

```
npm install @wp-playground/cli
```

2. Write a script like the following `cli.ts` :

```typescript
import { runCLI } from "@wp-playground/cli";

const script = `
<?php

$test = 42;

echo "Output!\n";

function test() {
	echo "Hello Xdebug World!\n";
}

test();
`;

const cliServer = await runCLI({command: 'server',  xdebug: true, experimentalDevtools: true});

await cliServer.playground.writeFile(`xdebug.php`, script);

const result = await cliServer.playground.run({scriptPath: `xdebug.php`});

console.log(result.text);
```

3. Run command : 

```
> node cli.js

Starting a PHP server...
Setting up WordPress undefined
Resolved WordPress release URL: https://downloads.w.org/release/wordpress-6.8.2.zip
Fetching SQLite integration plugin...
Booting WordPress...
Booted!
Running the Blueprint...
Running the Blueprint – 100%
Finished running the blueprint
WordPress is running on http://127.0.0.1:61859
Connect Chrome DevTools to CDP at:
devtools://devtools/bundled/inspector.html?ws=localhost:9229

...

Chrome connected! Initializing Xdebug receiver...
XDebug receiver running on port 9003
Running a PHP script with Xdebug enabled...
```

<img width="920" height="471" alt="screencapture"
src="https://github.com/user-attachments/assets/b3548d0e-f824-41c4-9148-3e4f106b4116"
/>

Note: It will need 23 step overs before leaving the
`auto_prepend_file.php` and entering the `xdebug.php` script.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants