Skip to content

Conversation

mho22
Copy link
Collaborator

@mho22 mho22 commented Jul 23, 2025

Motivation for the change, related issues

This pull request adds a --experimental-devtools option in php-wasm/cli.

Roadmap

Related issues and pull requests

Implementation details

  • Simple implementation of a Devtools option. It checks for a --experimental-devtools argument that starts the xdebug-to-cdp-bridge process.
  • Addition of external dependencies.

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();

In WordPress-Playground repository

  1. Run the php-wasm/cli command in a first terminal :
> nx run php-wasm-cli:dev --xdebug --experimental-devtools xdebug.php


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...
...

Output!
Hello Xdebug World!

In a non-related Playground project

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


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...
...

Output!
Hello Xdebug World!
screencapture

@mho22 mho22 requested a review from a team as a code owner July 23, 2025 21:08
@mho22 mho22 changed the title [ xdebug ] Add --cdp option in php-wasm CLI and wp-playground CLI [ xdebug ] Add --cdp option in php-wasm CLI and wp-playground CLI Jul 23, 2025
@mho22 mho22 mentioned this pull request Jul 22, 2025
11 tasks
@adamziel
Copy link
Collaborator

Let's call the option --devtools to make it less about the protocol and more about the user journey

@mho22 mho22 changed the title [ xdebug ] Add --cdp option in php-wasm CLI and wp-playground CLI [ xdebug ] Add --devtools option in php-wasm CLI and wp-playground CLI Jul 23, 2025
@mho22 mho22 mentioned this pull request Jul 23, 2025
@adamziel
Copy link
Collaborator

This PR seems to only affect @php-wasm/cli, which is fine, but the title and description also talk about @wp-playground/cli – was something lost during rebasing?

@mho22
Copy link
Collaborator Author

mho22 commented Jul 23, 2025

I'm currently working on getting it to run on wp-playground/cli. I just wanted to push my changes for php-wasm/cli and write the PR description for that part in the meantime.

@mho22
Copy link
Collaborator Author

mho22 commented Jul 23, 2025

I get this error when trying to start the bridge inside wp-playground/run-cli.ts file :

> node --no-warnings --experimental-wasm-stack-switching --experimental-wasm-jspi --loader=./packages/meta/src/node-es-module-loader/loader.mts ./playground.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:58879
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...
[XDebug][send] stdout -c 1
[XDebug][send] stderr -c 1
[XDebug][received]] 493<?xml version="1.0" encoding="iso-8859-1"?>
<init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" fileuri="file:///internal/shared/auto_prepend_file.php" language="PHP" xdebug:language_version="8.4.10-dev" protocol_version="1.0" appid="42"><engine version="3.4.6-dev"><![CDATA[Xdebug]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[https://xdebug.org]]></url><copyright><![CDATA[Copyright (c) 2002-2025 by Derick Rethans]]></copyright></init>
[XDebug][send] step_into undefined
[CDP][send] {"method":"Debugger.scriptParsed","params":{"scriptId":"1","url":"file:///internal/shared/auto_prepend_file.php","startLine":0,"startColumn":0,"executionContextId":1}}
[CDP][send] {"method":"Debugger.scriptParsed","params":{"scriptId":"1","url":"file:///internal/shared/auto_prepend_file.php","startLine":0,"startColumn":0,"executionContextId":1}}
[XDebug][received]] 192<?xml version="1.0" encoding="iso-8859-1"?>
<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="stdout" transaction_id="1" success="1"></response>192<?xml version="1.0" encoding="iso-8859-1"?>
<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="stderr" transaction_id="2" success="0"></response>311<?xml version="1.0" encoding="iso-8859-1"?>
<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="step_into" transaction_id="3" status="break" reason="ok"><xdebug:message filename="file:///internal/shared/auto_prepend_file.php" lineno="3"></xdebug:message></response>
[XDebug][send] stack_get undefined
[XDebug][received]] 303<?xml version="1.0" encoding="iso-8859-1"?>
<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="stack_get" transaction_id="4"><stack where="{main}" level="0" type="file" filename="file:///internal/shared/auto_prepend_file.php" lineno="3"></stack></response>
[CDP][send] {"method":"Debugger.paused","params":{"reason":"pause","callFrames":[{"callFrameId":"frame:0","functionName":"(anonymous)","location":{"scriptId":"1","lineNumber":2,"columnNumber":0},"scopeChain":[{"type":"local","object":{"objectId":"1","className":"Object","description":"Local"}},{"type":"global","object":{"objectId":"2","className":"Object","description":"Global"}}],"this":{"type":"object","className":"Object","description":"Object","objectId":"2"}}],"hitBreakpoints":[]}}
[CDP][received] {"id":42,"method":"Overlay.setPausedInDebuggerMessage","params":{"message":"Paused in debugger"}}
[CDP][send] {"id":42,"result":{}}
[CDP][received] {"id":43,"method":"Debugger.getScriptSource","params":{"scriptId":"1"}}
node:fs:443
    return binding.readFileUtf8(path, stringToFlags(options.flag));
                   ^

Error: ENOENT: no such file or directory, open '/internal/shared/auto_prepend_file.php'

I had to treat how it finds the php files differently by using the playground's readFileAsText instead of a regular PHP instance [ one is a Promise while the other is a string ] :

if (args.devtools) {
	const bridge = await startBridge({ getPHPFile : async (path: string) => await playground!.readFileAsText(path) });

	bridge.start();
}

This meant refactoring the getPHPFile in start-bridge.ts file and xdebug-cdp-bridge.ts.

I successfully made the devtools and xdebug work together by breaking on auto_prepend_file file when running this command :

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

This is playground.ts

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( { php : '8.4', command : 'server', xdebug : true, devtools : true } );

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

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

console.log( result.text );
screencapture

This is not my xdebug.php script yet, but it is kinda cool. I should investigate further tomorrow.

@adamziel
Copy link
Collaborator

adamziel commented Jul 23, 2025

Nice! If changes for Playground CLI will take more than a day, let's split them into another PR and add the @php-wasm/cli option. I've just audited the devtools bridge and it seems to have some shortcomings we'll need to work on – maybe let's change the option name again to --experimental-devtools to make it very clear this is a work in progress.

@mho22
Copy link
Collaborator Author

mho22 commented Jul 23, 2025

Ok! Let's split the pull request then. I am on it.

@mho22 mho22 changed the title [ xdebug ] Add --devtools option in php-wasm CLI and wp-playground CLI [ xdebug ] Add --devtools option in php-wasm CLI Jul 23, 2025
@mho22 mho22 changed the title [ xdebug ] Add --devtools option in php-wasm CLI [ xdebug ] Add --experimental-devtools option in php-wasm CLI Jul 23, 2025
@adamziel adamziel merged commit a064680 into trunk Jul 24, 2025
23 of 25 checks passed
@adamziel adamziel deleted the add-cdp-option-in-cli branch July 24, 2025 08:10
@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