From 1d61fefe5cd5363c98973baf41bf84e1b1f3dddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Tue, 28 Apr 2026 17:00:34 +0200 Subject: [PATCH] Conditional WASM wp_mysql_parser extension loader (PHP 8.4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wires up the MySQL lexer/parser extension from WordPress/sqlite-database-integration#381 as a Playground side module, gated to PHP 8.4 in this run while we have no broader build matrix to test against. Other versions throw a clear error. The bundled .so itself is not included — Playground has no published artifact yet. Users build the extension themselves and pass the path via: npx @wp-playground/cli server --php=8.4 \ --wp-mysql-parser-so=/path/to/wp_mysql_parser.so Implementation reuses the helper from the previous PR in the stack: the wrapper is a thin EmscriptenOptions adapter that calls installPHPExtensionFilesSync() in onRuntimeInitialized, identical in shape to with-xdebug and with-intl. CLI plumbing covers Blueprints v1 only; v2 wiring is a follow-up. --- .../wp-mysql-parser/with-wp-mysql-parser.ts | 65 +++++++++++++++++++ .../php-wasm/node/src/lib/load-runtime.ts | 12 ++++ .../blueprints-v1/blueprints-v1-handler.ts | 1 + .../cli/src/blueprints-v1/worker-thread-v1.ts | 4 ++ packages/playground/cli/src/run-cli.ts | 9 +++ 5 files changed, 91 insertions(+) create mode 100644 packages/php-wasm/node/src/lib/extensions/wp-mysql-parser/with-wp-mysql-parser.ts diff --git a/packages/php-wasm/node/src/lib/extensions/wp-mysql-parser/with-wp-mysql-parser.ts b/packages/php-wasm/node/src/lib/extensions/wp-mysql-parser/with-wp-mysql-parser.ts new file mode 100644 index 00000000000..cc9fc349195 --- /dev/null +++ b/packages/php-wasm/node/src/lib/extensions/wp-mysql-parser/with-wp-mysql-parser.ts @@ -0,0 +1,65 @@ +import { + type EmscriptenOptions, + type PHPRuntime, + type SupportedPHPVersion, + installPHPExtensionFilesSync, + PHP_EXTENSIONS_DIR, +} from '@php-wasm/universal'; +import fs from 'fs'; + +export interface WpMysqlParserOptions { + /** + * Absolute path on the host filesystem to a `wp_mysql_parser.so` side + * module compiled for the target PHP version and async mode. + * + * The extension itself lives at + * https://github.com/WordPress/sqlite-database-integration/pull/381 + * and is not yet packaged with Playground; users build it themselves + * (or fetch it from a release artifact) and pass the path via + * `--wp-mysql-parser-so=` on the CLI. + */ + soPath: string; +} + +/* + * The PR #381 build hasn't been validated against earlier PHP versions + * yet, so this run only wires it up for PHP 8.4. Widening to other + * versions is a one-line change once we have artifacts to test against. + */ +const SUPPORTED_VERSIONS: ReadonlyArray = ['8.4']; + +export async function withWpMysqlParser( + version: SupportedPHPVersion, + options: EmscriptenOptions, + wpMysqlParserOptions: WpMysqlParserOptions +): Promise { + if (!SUPPORTED_VERSIONS.includes(version)) { + throw new Error( + `withWpMysqlParser: only PHP ${SUPPORTED_VERSIONS.join( + ', ' + )} are supported in this build; got ${version}.` + ); + } + + const soBytes = new Uint8Array( + fs.readFileSync(wpMysqlParserOptions.soPath) + ); + + return { + ...options, + ENV: { + ...options.ENV, + PHP_INI_SCAN_DIR: PHP_EXTENSIONS_DIR, + }, + onRuntimeInitialized: (phpRuntime: PHPRuntime) => { + if (options.onRuntimeInitialized) { + options.onRuntimeInitialized(phpRuntime); + } + + installPHPExtensionFilesSync(phpRuntime.FS, { + name: 'wp_mysql_parser', + soBytes, + }); + }, + }; +} diff --git a/packages/php-wasm/node/src/lib/load-runtime.ts b/packages/php-wasm/node/src/lib/load-runtime.ts index 6bf92ca982e..229d45eea4d 100644 --- a/packages/php-wasm/node/src/lib/load-runtime.ts +++ b/packages/php-wasm/node/src/lib/load-runtime.ts @@ -25,6 +25,10 @@ import { import { withIntl } from './extensions/intl/with-intl'; import { withRedis } from './extensions/redis/with-redis'; import { withMemcached } from './extensions/memcached/with-memcached'; +import { + withWpMysqlParser, + type WpMysqlParserOptions, +} from './extensions/wp-mysql-parser/with-wp-mysql-parser'; import { dirname, joinPaths, toPosixPath } from '@php-wasm/util'; import { platform } from 'os'; @@ -34,6 +38,7 @@ export interface PHPLoaderOptions { withIntl?: boolean; withRedis?: boolean; withMemcached?: boolean; + withWpMysqlParser?: WpMysqlParserOptions; } export type PHPLoaderOptionsForNode = PHPLoaderOptions & { @@ -344,6 +349,13 @@ export async function loadNodeRuntime( emscriptenOptions ); } + if (options?.withWpMysqlParser) { + emscriptenOptions = await withWpMysqlParser( + modernVersion, + emscriptenOptions, + options.withWpMysqlParser + ); + } } emscriptenOptions = await withNetworking(emscriptenOptions); diff --git a/packages/playground/cli/src/blueprints-v1/blueprints-v1-handler.ts b/packages/playground/cli/src/blueprints-v1/blueprints-v1-handler.ts index a30ca4e01b0..5a7bdaf15ca 100644 --- a/packages/playground/cli/src/blueprints-v1/blueprints-v1-handler.ts +++ b/packages/playground/cli/src/blueprints-v1/blueprints-v1-handler.ts @@ -201,6 +201,7 @@ export class BlueprintsV1Handler { withRedis: this.args.redis, withMemcached: this.args.memcached, withXdebug: !!this.args.xdebug, + withWpMysqlParserSo: this.args['wp-mysql-parser-so'], nativeInternalDirPath, pathAliases: this.args.pathAliases, }); diff --git a/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts b/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts index a5defa6d70b..62806c0d341 100644 --- a/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts +++ b/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts @@ -52,6 +52,7 @@ interface WorkerBootRequestHandlerOptions { withRedis?: boolean; withMemcached?: boolean; withXdebug?: boolean; + withWpMysqlParserSo?: string; pathAliases?: PathAlias[]; } @@ -251,6 +252,9 @@ function createPhpRuntimeFactory( withRedis: options.withRedis, withMemcached: options.withMemcached, withXdebug: options.withXdebug, + withWpMysqlParser: options.withWpMysqlParserSo + ? { soPath: options.withWpMysqlParserSo } + : undefined, } ); }; diff --git a/packages/playground/cli/src/run-cli.ts b/packages/playground/cli/src/run-cli.ts index b1e7245c48a..e822437baf0 100644 --- a/packages/playground/cli/src/run-cli.ts +++ b/packages/playground/cli/src/run-cli.ts @@ -299,6 +299,14 @@ export async function parseOptionsAndRunCLI(argsToParse: string[]) { type: 'boolean', default: false, }, + 'wp-mysql-parser-so': { + describe: + 'Path to a wp_mysql_parser.so side module compiled for the ' + + 'target PHP version. Only PHP 8.4 is supported in this build. ' + + 'See https://github.com/WordPress/sqlite-database-integration/pull/381', + type: 'string', + normalize: true, + }, 'experimental-unsafe-ide-integration': { describe: 'Enable experimental IDE development tools. This option edits IDE config files ' + @@ -890,6 +898,7 @@ export interface RunCLIArgs { redis?: boolean; memcached?: boolean; xdebug?: boolean | XdebugOptions; + 'wp-mysql-parser-so'?: string; experimentalUnsafeIdeIntegration?: string[]; experimentalDevtools?: boolean; 'experimental-blueprints-v2-runner'?: boolean;