-
Notifications
You must be signed in to change notification settings - Fork 316
Debug PHP in browser Devtools (XDebug <-> CDP Bridge) #2288
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
base: trunk
Are you sure you want to change the base?
Conversation
@adamziel I'm impressed. A great way to begin my day. I need to dive deeper into that protocol. |
@adamziel, this looks awesome! |
Or should we do WebDriver BiDi instead? Firefox is retiring its CDP support: https://fxdx.dev/cdp-retirement-in-firefox/
|
Probably? BiDi seems to be a better long-term solution but is not yet ready for WebKit. On the other hand, we would definitely lose Firefox support with CDP. |
…#2326) ## Motivation for the change This is a pull request to dynamically load Xdebug in `@php-wasm` Node ASYNCIFY. [Roadmap](#2315) ## Related issues and pull requests Relative to XDebug - #2248 - #314 - #2288 - #831 Relative to dynamic library - #89 - #2290 - #673 ## Implementation details Additional steps for asyncify are implemented : - new nx commands - new `WITH_JSPI` and `WITH_DEBUG` arguments in Xdebug Dockerfile - new `xdebug.so` files are compiled and dynamically loaded ## Zend extensions and PHP versions > [!IMPORTANT] > Each version of PHP requires its own version of Xdebug because each version of PHP has a specific Zend Engine API version. Consequently, each version of Xdebug is designed to be compatible with a particular Zend Engine API version. Example using PHP `8.2` with Xdebug `8.3` : ``` Xdebug requires Zend Engine API version 420230831. The Zend Engine API version 420220829 which is installed, is outdated. ``` ## Testing Instructions Two files are needed. A PHP file to test the step debugger. A JS file to run PHP 8.4 node ASYNCIFY. `php/xdebug.php` ```php <?php $test = 42; // Set a breakpoint on this line echo "Hello Xdebug World\n"; ``` `scripts/node.js` ```javascript import { PHP } from '@php-wasm/universal'; import { loadNodeRuntime } from '@php-wasm/node'; const php = new PHP( await loadNodeRuntime( '8.4', { withXdebug : true } ) ); await php.runStream( { scriptPath : `php/xdebug.php` } ); ``` To achieve the test, you first need to start debugging [ with F5 or Run > Start debugging in VSCode ], then run : ```bash node scripts/node.js ```
## Motivation for the change, related issues Adds a mock, AI-generated `@php-wasm/xdebug-bridge` package to jumpstart the work on [XDebug in browser devtools](#2288). Cursor prompt: > Create a new package `@php-wasm/xdebug-bridge` with a startXDebugBridge() function that starts a plain network server, It should accept a few config params via an object, e.g. protocol ("cdp"), xdebugServerPort (number, default to xdebug default port). > > It should also ship a CLI script that can be used to run that function from CLI. Accept CLI args, print useful information, but make sure startXDebugBridge() can still be executed without printing anything to console. ## Testing Instructions (or ideally a Blueprint) Confirm it doesn't break the CI. cc @mho22
## Motivation for the change, related issues Populates the new `php-wasm-xdebug-bridge` package which will connect Xdebug with Browser Devtools. [Roadmap](#2315) ## Related issues and pull requests - #2346 - #2398 - #2288 ## 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 <?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... ``` 2. 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 ``` 2. 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... ``` 3. Run the `@php-wasm/cli` command in a second terminal : ``` > npx cli --xdebug xdebug.php Output! Hello Xdebug World! ``` <img width="748" height="409" alt="screencapture" src="https://github.com/user-attachments/assets/b0232831-c9b3-4bb2-95aa-b1d51b72766e" /> --------- Co-authored-by: mho22 <[email protected]>
) ## 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.
Motivation for the change, related issues
An XDebug <-> CDP bridge to debug PHP code in the browser:
CleanShot.2025-06-19.at.01.59.06.mp4
Implementation details
I've asked o3-pro to build it, applied a few tweaks, and voila – we have a a demo :-)
Testing Instructions (or ideally a Blueprint)
The script will guide you from there
Problems
When
eval
is called, PHP crashes like below. It may be a bridge problem or XDebug problem:cc @mho22 @brandonpayton @akirk @wojtekn @griffbrad @bgrgicak