Build wp_mysql_parser to wasm and gate it in CI#395
Open
Conversation
Spike confirms the Rust extension can be compiled to a PHP-wasm side module via @php-wasm/compile-extension and loaded into Playground. Build recipe and findings live in wasm-spike/RESULT.md; the new GitHub Actions workflow runs the build against wordpress-playground trunk on every PR that touches the extension and verifies the produced .so loads and parses a query. The workflow currently fails on a Playground-side blocker (zend_ce_traversable not exported from PHP-wasm's MAIN_MODULE=2 export set). RESULT.md documents the blocker and the proposed fix in WordPress/wordpress-playground.
The previous workflow assumed playground-php-wasm:compile-extension-php8-4-jspi was already present in the Docker daemon (which it is locally, after running the @php-wasm/compile-extension CLI once). On a fresh runner it isn't, so Dockerfile.rust failed at FROM with 'pull access denied'. Build it explicitly: 'make base-image' for the Emscripten toolchain layer, then docker build of compile-extension/docker/Dockerfile.ext with the same PHP_VERSION the CLI's resolvePHPRelease() would pick, tagged the way the CLI tags it (dots replaced with dashes).
The wasm-spike workflow needs @php-wasm/compile-extension's source map and load-built-extension.mjs harness, neither of which exist on wordpress-playground trunk. They live on the adamziel/compile-extension branch (PR #3582). Default the checkout there so the resolvePHPRelease step can read compile.ts and run-spike.mjs can find the harness.
The base-image build fails inside the daemon's default bridge network with 'Could not resolve archive.ubuntu.com', causing apt-get to skip every package. Configure /etc/docker/daemon.json with public resolvers (8.8.8.8, 1.1.1.1) and restart the daemon so the build container can reach Ubuntu mirrors.
The build script never wrote dist/manifest.json, so the verify step failed. Generate it from the @php-wasm/compile-extension manifest schema (name/version/artifacts[]) right after the side-module link, fix the workflow's sha-extraction (manifest.artifacts[0], not manifest.extensions[0].artifacts[0]), and drop the stale ASYNC_MODE positional arg from run-spike.mjs so the args line up with load-built-extension.mjs's <manifest> <php> <code> <expected> shape.
External extensions only load under JSPI, but loadNodeRuntime decides the mode by asking wasm-feature-detect, not by trusting our flag. Run the same probe up front so a failure surfaces with a clear message instead of the runtime's generic 'External PHP extensions require JSPI'.
wasm-feature-detect's jspi probe checks for WebAssembly.Suspending in the WebAssembly namespace. Node 22.22.2 with --experimental-wasm-jspi does not expose it, so loadNodeRuntime falls back to asyncify and rejects external extensions. Node 24 has JSPI enabled, so the probe succeeds and the runtime accepts our side module.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Spike confirms the new Rust MySQL parser can be compiled to a PHP-wasm side module via Playground's
@php-wasm/compile-extension(PR #3582) and loaded at runtime. This PR lands the build recipe plus a CI job that builds the side module on every parser change and verifies it loads inside a freshly-checked-out Playground.The full investigation lives in
packages/php-ext-wp-mysql-parser/wasm-spike/RESULT.md— every workaround the build needs (host-PHP graft into the compile-extension image, bindgen sysroot,-fPIC,-Zbuild-std=std,panic_abortto drop Rust'spanic=unwindlibstd) is documented there with the underlying error each one fixes.The CI job is intentionally narrow: PHP 8.4, JSPI only. The point isn't a release matrix — it's to gate the green path. Expanding to 7.2 → 8.5 is a follow-up once the headline blocker lands.
That blocker:
MAIN_MODULE=2in PHP-wasm exports a 30-line SAPI list, which doesn't includezend_ce_traversableand the other Zend class-entry globals that ext-php-rs imports. No existing Playground extension hits this because everything shipping today is statically linked into MAIN_MODULE — this PR's side module is the first to need those exports. The Playground-side fix is a small__attribute__((used))keep-alive C file inpackages/php-wasm/compile/php/; details and the exact symbol list (measured withwasm-objdump) are in RESULT.md.Until the Playground export-list change merges and the CI job's
playground-refdefault is bumped to a build that includes it, this workflow will fail at thenode run-spike.mjsstep. That's the intended behavior — the failure is the whole signal that A1 is still pending.The workflow accepts a
playground-refworkflow_dispatchinput so you can point it at a specific Playground branch (e.g. the export-list PR) for ad-hoc verification before that PR merges to trunk.