Skip to content

Commit 94fd429

Browse files
authored
[ xdebug ] Add --experimental-devtools option in Playground CLI (#2411)
## 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.
1 parent 2c8f89e commit 94fd429

File tree

3 files changed

+36
-14
lines changed

3 files changed

+36
-14
lines changed

packages/php-wasm/xdebug-bridge/src/lib/start-bridge.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export type StartBridgeConfig = {
1414
localRoot?: string;
1515

1616
phpInstance?: PHP;
17-
getPHPFile?: (path: string) => string;
17+
getPHPFile?: (path: string) => Promise<string>;
1818
};
1919

2020
export async function startBridge(config: StartBridgeConfig) {
@@ -58,17 +58,21 @@ export async function startBridge(config: StartBridgeConfig) {
5858
}
5959

6060
const getPHPFile = config.phpInstance
61-
? (path: string) => config.phpInstance!.readFileAsText(path)
61+
? (path: string) =>
62+
new Promise<string>(() =>
63+
config.phpInstance!.readFileAsText(path)
64+
)
6265
: config.getPHPFile
6366
? config.getPHPFile
64-
: (path: string) => {
65-
// Default implementation: read from filesystem
66-
// Convert file:/// URLs to local paths
67-
const localPath = path.startsWith('file://')
68-
? path.replace('file://', '')
69-
: path;
70-
return readFileSync(localPath, 'utf-8');
71-
};
67+
: (path: string) =>
68+
new Promise<string>(() => {
69+
// Default implementation: read from filesystem
70+
// Convert file:/// URLs to local paths
71+
const localPath = path.startsWith('file://')
72+
? path.replace('file://', '')
73+
: path;
74+
return readFileSync(localPath, 'utf-8');
75+
});
7276

7377
const phpFiles = getPhpFiles(phpRoot);
7478
return new XdebugCDPBridge(dbgpSession, cdpServer, {

packages/php-wasm/xdebug-bridge/src/lib/xdebug-cdp-bridge.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export interface XdebugCDPBridgeConfig {
2828
knownScriptUrls: string[];
2929
remoteRoot?: string;
3030
localRoot?: string;
31-
getPHPFile(path: string): string;
31+
getPHPFile(path: string): Promise<string>;
3232
}
3333

3434
export class XdebugCDPBridge {
@@ -45,7 +45,7 @@ export class XdebugCDPBridge {
4545
private xdebugConnected = false;
4646
private xdebugStatus = 'starting';
4747
private initFileUri: string | null = null;
48-
private readPHPFile: (path: string) => string;
48+
private readPHPFile: (path: string) => Promise<string>;
4949
private remoteRoot: string;
5050
private localRoot: string;
5151

@@ -212,7 +212,7 @@ export class XdebugCDPBridge {
212212
return txnIdStr;
213213
}
214214

215-
private handleCdpMessage(message: any) {
215+
private async handleCdpMessage(message: any) {
216216
const { id, method, params } = message;
217217
let result: any = {};
218218
let sendResponse = true;
@@ -423,7 +423,9 @@ export class XdebugCDPBridge {
423423
)?.[0];
424424
let scriptSource = '';
425425
if (uri) {
426-
scriptSource = this.readPHPFile(this.uriToRemotePath(uri));
426+
scriptSource = await this.readPHPFile(
427+
this.uriToRemotePath(uri)
428+
);
427429
}
428430
result = { scriptSource };
429431
break;

packages/playground/cli/src/run-cli.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import { isValidWordPressSlug } from './is-valid-wordpress-slug';
4747
import { resolveBlueprint } from './resolve-blueprint';
4848
import { BlueprintsV2Handler } from './blueprints-v2/blueprints-v2-handler';
4949
import { BlueprintsV1Handler } from './blueprints-v1/blueprints-v1-handler';
50+
import { startBridge } from '@php-wasm/xdebug-bridge';
5051

5152
export async function parseOptionsAndRunCLI() {
5253
try {
@@ -184,6 +185,11 @@ export async function parseOptionsAndRunCLI() {
184185
type: 'boolean',
185186
default: false,
186187
})
188+
.option('experimental-devtools', {
189+
describe: 'Enable experimental browser development tools.',
190+
type: 'boolean',
191+
default: false,
192+
})
187193
// TODO: Should we make this a hidden flag?
188194
.option('experimental-multi-worker', {
189195
describe:
@@ -301,6 +307,7 @@ export interface RunCLIArgs {
301307
internalCookieStore?: boolean;
302308
'additional-blueprint-steps'?: any[];
303309
xdebug?: boolean;
310+
experimentalDevtools?: boolean;
304311
'experimental-blueprints-v2-runner'?: boolean;
305312

306313
// --------- Blueprint V1 args -----------
@@ -535,6 +542,15 @@ export async function runCLI(args: RunCLIArgs): Promise<RunCLIServer> {
535542

536543
logger.log(`WordPress is running on ${absoluteUrl}`);
537544

545+
if (args.experimentalDevtools && args.xdebug) {
546+
const bridge = await startBridge({
547+
getPHPFile: async (path: string) =>
548+
await playground!.readFileAsText(path),
549+
});
550+
551+
bridge.start();
552+
}
553+
538554
return {
539555
playground,
540556
server,

0 commit comments

Comments
 (0)