playground-tools icon indicating copy to clipboard operation
playground-tools copied to clipboard

wp-now: Update Playground and PHP WASM dependencies

Open eliot-akira opened this issue 1 year ago • 11 comments

What?

This pull request is a continuation of #345 to update Playground dependencies from 0.6.16 to 0.9.39 and adapt existing code to work with breaking changes.

Resolves #319.

Why?

To keep up with upstream changes and benefit from new features and bug fixes.

How?

Update to new interface for PHP runtime instances, requests, and file system mount.

Based on similar logic in @wp-playground/wordpress (bootWordpress) and cli.

  • Use PHP class from @php-wasm/universal instead of NodePHP from @php-wasm/node, which no longer exists.
    • WordPress/wordpress-playground#1457
  • Use PHPRequestHandler instead of php.request()
  • Use createNodeFsMountHandler to mount the file system with Node-specific adaptor for php.mount()
  • Remove logic that handled PHP instances manually

Further changes were necessary to pass all existing tests.

  • Update executeWpCli based on fork of wp-now in Automattic/studio
    • Use TLS certificates
    • Workaround for stdin/out/err
    • Not implemented yet: SQLite command
  • Update @php-wasm/compile to add any missing C functions to the list in ASYNCIFY_IMPORTS in the Dockerfile here.
    • Documentation about WASM errors related to Asyncify: https://wordpress.github.io/wordpress-playground/developers/architecture/wasm-asyncify/#asyncify-crashes

Testing Instructions

  • npx nx test wp-now

eliot-akira avatar Aug 27 '24 16:08 eliot-akira

Currently there are 3 failing tests, as seen in the CI logs.

They're about running PHP as CLI, and about WP-CLI.

 ❯ src/tests/wp-now.spec.ts  (46 tests | 3 failed | 1 skipped) 70720ms
   ❯ src/tests/wp-now.spec.ts > Test starting different modes > validate php comand arguments passed through yargs > php should execute a file
     → expected '' to match /8\.0/i
   ❯ src/tests/wp-now.spec.ts > Test starting different modes > validate php comand arguments passed through yargs > php should execute a file and change php version
     → expected '' to match /7\.4/i
   ❯ src/tests/wp-now.spec.ts > wp-cli command > wp-cli displays the version
     → Program terminated with exit(1)

There are also WASM errors associated with the PHP CLI tests, both:

RuntimeError: null function or function signature mismatch

That could be related to a similar error described in:

  • WordPress/wordpress-playground#1716

I'll copy the WASM error stack traces below for reference. They're slightly different, so might have different causes.

stderr | src/tests/wp-now.spec.ts > Test starting different modes > validate php comand arguments passed through yargs > php should execute a file

RuntimeError: null function or function signature mismatch
    at php_auto_globals_create_get (wasm://wasm/php.wasm-0380e0be:1:6470748)
    at php_hash_environment (wasm://wasm/php.wasm-0380e0be:1:6417625)
    at dynCall_i (wasm://wasm/php.wasm-0380e0be:1:7251146)
    at ret.<computed> (file://~/playground-tools/node_modules/@php-wasm/node/index.js:29057:22)
    at t.wasmExports.<computed> (file://~/playground-tools/node_modules/@php-wasm/universal/index.js:522:18)
    at invoke_i (file://~/playground-tools/node_modules/@php-wasm/node/index.js:29675:14)
    at php_request_startup (wasm://wasm/php.wasm-0380e0be:1:2685484)
    at dynCall_i (wasm://wasm/php.wasm-0380e0be:1:7251146)
    at ret.<computed> (file://~/playground-tools/node_modules/@php-wasm/node/index.js:29057:22)
    at t.wasmExports.<computed> (file://~/playground-tools/node_modules/@php-wasm/universal/index.js:522:18)
    at invoke_i (file://~/playground-tools/node_modules/@php-wasm/node/index.js:29675:14)
    at do_cli (wasm://wasm/php.wasm-0380e0be:1:7284591)
    at dynCall_iii (wasm://wasm/php.wasm-0380e0be:1:7250788)
    at ret.<computed> (file://~/playground-tools/node_modules/@php-wasm/node/index.js:29057:22)
    at t.wasmExports.<computed> (file://~/playground-tools/node_modules/@php-wasm/universal/index.js:522:18)
    at invoke_iii (file://~/playground-tools/node_modules/@php-wasm/node/index.js:29598:14) {
  cause: Error: 
      at Object.Asyncify.handleSleep (file://~/playground-tools/node_modules/@php-wasm/node/index.js:29857:45)
      at _wasm_poll_socket (file://~/playground-tools/node_modules/@php-wasm/node/index.js:28922:21)
      at php_pollfd_for (wasm://wasm/php.wasm-0380e0be:1:633716)
      at php_network_connect_socket (wasm://wasm/php.wasm-0380e0be:1:3934833)
      at php_tcp_sockop_set_option (wasm://wasm/php.wasm-0380e0be:1:6332023)
      at php_openssl_sockop_set_option (wasm://wasm/php.wasm-0380e0be:1:6373167)
      at _php_stream_set_option (wasm://wasm/php.wasm-0380e0be:1:252064)
      at dynCall_iiiii (wasm://wasm/php.wasm-0380e0be:1:7250364)
      at ret.<computed> (file://~/playground-tools/node_modules/@php-wasm/node/index.js:29057:22)
      at t.wasmExports.<computed> (file://~/playground-tools/node_modules/@php-wasm/universal/index.js:522:18)
      at invoke_iiiii (file://~/playground-tools/node_modules/@php-wasm/node/index.js:29609:14)
      at _php_stream_xport_create (wasm://wasm/php.wasm-0380e0be:1:1105389)
      at zif_stream_socket_client (wasm://wasm/php.wasm-0380e0be:1:5252366)
      at ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_HANDLER (wasm://wasm/php.wasm-0380e0be:1:7683052)
      at execute_ex (wasm://wasm/php.wasm-0380e0be:1:7135045)
      at zend_execute (wasm://wasm/php.wasm-0380e0be:1:2359117)
}

stderr | src/tests/wp-now.spec.ts > Test starting different modes > validate php comand arguments passed through yargs > php should execute a file and change php version

RuntimeError: null function or function signature mismatch
    at php_auto_globals_create_get (wasm://wasm/php.wasm-039ec376:1:6739627)
    at null.<anonymous> (wasm://wasm/php.wasm-039ec376:1:8576690)
    at php_hash_environment (wasm://wasm/php.wasm-039ec376:1:6669088)
    at null.<anonymous> (wasm://wasm/php.wasm-039ec376:1:8452698)
    at dynCall_i (wasm://wasm/php.wasm-039ec376:1:7679921)
    at ret.<computed> (file://~/playground-tools/node_modules/@php-wasm/node/index.js:36486:22)
    at t.wasmExports.<computed> (file://~/playground-tools/node_modules/@php-wasm/universal/index.js:522:18)
    at invoke_i (file://~/playground-tools/node_modules/@php-wasm/node/index.js:37035:14)
    at php_request_startup (wasm://wasm/php.wasm-039ec376:1:2843395)
    at null.<anonymous> (wasm://wasm/php.wasm-039ec376:1:8448590)
    at dynCall_i (wasm://wasm/php.wasm-039ec376:1:7679921)
    at ret.<computed> (file://~/playground-tools/node_modules/@php-wasm/node/index.js:36486:22)
    at t.wasmExports.<computed> (file://~/playground-tools/node_modules/@php-wasm/universal/index.js:522:18)
    at invoke_i (file://~/playground-tools/node_modules/@php-wasm/node/index.js:37035:14)
    at do_cli (wasm://wasm/php.wasm-039ec376:1:7715417)
    at null.<anonymous> (wasm://wasm/php.wasm-039ec376:1:8448901) {
  cause: Error: 
      at Object.Asyncify.handleSleep (file://~/playground-tools/node_modules/@php-wasm/node/index.js:37272:45)
      at _wasm_poll_socket (file://~/playground-tools/node_modules/@php-wasm/node/index.js:36351:21)
      at php_pollfd_for (wasm://wasm/php.wasm-039ec376:1:622857)
      at php_network_connect_socket (wasm://wasm/php.wasm-039ec376:1:4156375)
      at php_tcp_sockop_set_option (wasm://wasm/php.wasm-039ec376:1:6572034)
      at null.<anonymous> (wasm://wasm/php.wasm-039ec376:1:8570026)
      at php_openssl_sockop_set_option (wasm://wasm/php.wasm-039ec376:1:6613667)
      at null.<anonymous> (wasm://wasm/php.wasm-039ec376:1:8538339)
      at _php_stream_set_option (wasm://wasm/php.wasm-039ec376:1:264442)
      at _php_stream_xport_create (wasm://wasm/php.wasm-039ec376:1:1195532)
      at zif_stream_socket_client (wasm://wasm/php.wasm-039ec376:1:5474793)
      at null.<anonymous> (wasm://wasm/php.wasm-039ec376:1:8561025)
      at ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_HANDLER (wasm://wasm/php.wasm-039ec376:1:8131754)
      at null.<anonymous> (wasm://wasm/php.wasm-039ec376:1:8581554)
      at execute_ex (wasm://wasm/php.wasm-039ec376:1:7554683)
      at null.<anonymous> (wasm://wasm/php.wasm-039ec376:1:8591528)
}

I checked the called php_ functions to ensure they're listed in the ASYNCIFY_IMPORTS in the Dockerfile for compiling PHP to WASM. They all seem to be there, but I might have missed something.

  • https://github.com/WordPress/wordpress-playground/blob/2975b41ced95054ab3332cad41f27af557309b08/packages/php-wasm/compile/php/Dockerfile#L439

I saw that a similar update of Playground and PHP-WASM dependencies happened in:

  • https://github.com/Automattic/studio/pull/491

The project includes a vendored and patched wp-now. Looks like they had to implement a tricky workaround to make WP-CLI work, but I'm hoping that won't be necessary to copy over; otherwise that would probably be better as a separate PR for the Playground repo, as a prerequisite for this one.

One difference I noticed is setting up TLS root certificates.

  • https://github.com/Automattic/studio/pull/491/files#diff-952f2fb6ea000e9e9dcd9d21f7740b883493d4235bf24b5086745a18b6e14b36

I'll try that and some other relevant changes, and see if it helps with passing the remaining tests.

eliot-akira avatar Sep 02 '24 20:09 eliot-akira

@sejas poke for the reviews! :-)

adamziel avatar Sep 06 '24 19:09 adamziel

As for the unreachable errors, it might require a PR similar to https://github.com/WordPress/wordpress-playground/pull/1716 that adds all the C functions from the stack trace to the Dockerfile. See https://wordpress.github.io/wordpress-playground/developers/architecture/wasm-asyncify/#asyncify-crashes

adamziel avatar Sep 06 '24 19:09 adamziel

OK, down to 2 failing tests, both about PHP CLI and WASM errors.

it might require a PR that..adds all the C functions from the stack trace to the Dockerfile.

I need help with solving the WASM part - as far as I can see, all the C functions are already listed in ASYNCIFY_IMPORTS in the Dockerfile of @php-wasm/compile here. I'll go through them again to make sure I didn't miss anything.


For the WP-CLI test that was failing before, I ported the changes in executeWpCli from the fork of wp-now in Automattic/studio:

  • https://github.com/Automattic/studio/blob/trunk/vendor/wp-now/src/execute-wp-cli.ts

It includes a somewhat gnarly workaround to make WP-CLI work. Some of this might be suitable to move upstream as shared logic in @wp-playground/wordpress or cli.

One part I had to comment out, about SQLite command. Maybe this could be left for another PR to more fully develop the WP-CLI integration, which is (I think) not yet part of the public interface of wp-now.

eliot-akira avatar Sep 07 '24 15:09 eliot-akira

Here are the functions listed in the WASM error stacks (below). I combined and sorted them alphabetically, then checked each against the Dockerfile in @php-wasm/compile/php.

  • [x] _php_stream_set_option
  • [x] _php_stream_xport_create
  • [ ] _wasm_poll_socket
  • [x] dynCall_iiiii
  • [x] execute_ex
  • [x] php_network_connect_socket
  • [x] php_openssl_sockop_set_option
  • [x] php_pollfd_for
  • [x] php_tcp_sockop_set_option
  • [x] zend_execute
  • [x] zif_stream_socket_client

The missing one is _wasm_poll_socket. Looks like it may belong with the other _wasm_* functions in the Dockerfile as part of EXPORTED_FUNCTIONS instead of ASYNCIFY_IMPORT.

I can create a PR for this - but it might be better to try locally first, and see if it actually solves the issue. I guess in my local playground repo I'll recompile PHP-WASM with the change, then link the NPM package(s) to playground-tools and see if the tests pass.

There's an ongoing PR that updates the same Dockerfile, adds a number of C functions to the Asyncify list, and recompiles all versions of PHP WASM.

  • WordPress/wordpress-playground#1716

This could be the quickest solution to ask if they can add _wasm_poll_socket to EXPORTED_FUNCTIONS as part of their work.


...
cause: Error:
at Object.Asyncify.handleSleep (file://~/playground-tools/node_modules/@php-wasm/node/index.js:29857:45)
at _wasm_poll_socket (file://~/playground-tools/node_modules/@php-wasm/node/index.js:28922:21)
at php_pollfd_for (wasm://wasm/php.wasm-0381a85e:1:634630)
at php_network_connect_socket (wasm://wasm/php.wasm-0381a85e:1:3939767)
at php_tcp_sockop_set_option (wasm://wasm/php.wasm-0381a85e:1:6339293)
at php_openssl_sockop_set_option (wasm://wasm/php.wasm-0381a85e:1:6381905)
at _php_stream_set_option (wasm://wasm/php.wasm-0381a85e:1:252625)
at dynCall_iiiii (wasm://wasm/php.wasm-0381a85e:1:7262168)
at ret.<computed> (file://~/playground-tools/node_modules/@php-wasm/node/index.js:29057:22)
at t.wasmExports.<computed> (file://~/playground-tools/node_modules/@php-wasm/universal/index.js:522:18)
at invoke_iiiii (file://~/playground-tools/node_modules/@php-wasm/node/index.js:29609:14)
at _php_stream_xport_create (wasm://wasm/php.wasm-0381a85e:1:1106649)
at zif_stream_socket_client (wasm://wasm/php.wasm-0381a85e:1:5257722)
at ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_HANDLER (wasm://wasm/php.wasm-0381a85e:1:7695829)
at execute_ex (wasm://wasm/php.wasm-0381a85e:1:7146849)
at zend_execute (wasm://wasm/php.wasm-0381a85e:1:2361792)

...
cause: Error:
at Object.Asyncify.handleSleep (file://~/playground-tools/node_modules/@php-wasm/node/index.js:37272:45)
at _wasm_poll_socket (file://~/playground-tools/node_modules/@php-wasm/node/index.js:36351:21)
at php_pollfd_for (wasm://wasm/php.wasm-039fea6e:1:623826)
at php_network_connect_socket (wasm://wasm/php.wasm-039fea6e:1:4162312)
at php_tcp_sockop_set_option (wasm://wasm/php.wasm-039fea6e:1:6583506)
at null.<anonymous> (wasm://wasm/php.wasm-039fea6e:1:8588223)
at php_openssl_sockop_set_option (wasm://wasm/php.wasm-039fea6e:1:6626546)
at null.<anonymous> (wasm://wasm/php.wasm-039fea6e:1:8556536)
at _php_stream_set_option (wasm://wasm/php.wasm-039fea6e:1:265054)
at _php_stream_xport_create (wasm://wasm/php.wasm-039fea6e:1:1196959)
at zif_stream_socket_client (wasm://wasm/php.wasm-039fea6e:1:5481212)
at null.<anonymous> (wasm://wasm/php.wasm-039fea6e:1:8579222)
at ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_HANDLER (wasm://wasm/php.wasm-039fea6e:1:8148852)
at null.<anonymous> (wasm://wasm/php.wasm-039fea6e:1:8600108)
at execute_ex (wasm://wasm/php.wasm-039fea6e:1:7570728)
at null.<anonymous> (wasm://wasm/php.wasm-039fea6e:1:8610440)

eliot-akira avatar Sep 07 '24 22:09 eliot-akira

Next steps to complete this PR:

  • [x] In my local playground repo, add _wasm_poll_socket to the Dockerfile as part of EXPORTED_FUNCTIONS. Recompile PHP-WASM with the change. This takes a while.
    npm run recompile:php:node
    
    • Building all packages with npm run build fails:
      NX   Error: write EPIPE
      [NX Daemon Server] - Server stopped because: "Stopping the daemon the set of ignored files changed (native)"
      
      ✅ Solved by removing the cache folder:
      rm -rf node_modules/.cache
      npm run build
      
    • The task php-wasm-node:build:package-json fails for several PHP versions.
      ✘ [ERROR] Could not resolve "../../public/php_8_3.js"
      
          packages/php-wasm/node/src/lib/get-php-loader-module.ts:10:23:
            10 │       return await import(`../../public/php_8_3.js`);
               ╵                           ~~~~~~~~~~~~~~~~~~~~~~~~~
      
      ✅ Solved by compiling each version:
      for f in 7.0 7.1 7.2 7.3 7.4 8.0 8.1 8.2 8.3; do
        npm run recompile:php:node:$f
      done
      
  • [x] ~Link~ Copy built NPM package(s) to playground-tools/node_modules.
    • npm link doesn't work, it links to uncompiled source.
    • Manually creating symlinks to @php-wasm packages doesn't work. Modules importing each other lead to symlinks (created by npm or nx) within playground/node_modules with uncompiled source.
    • ✅ Just copy built packages from dist.
      cd playground-tools/node_modules/@php-wasm
      for f in *; do
        if [ -d "$f" ]; then
          echo "$f"
          rsync -r --delete ../../../playground/dist/packages/php-wasm/"$f"/ "$f"
        fi
      done
      
  • [ ] ❌ Confirm WASM errors are resolved and all tests pass.
    npx nx test wp-now
    
  • [ ] Create PR for the change in playground repo.
  • [ ] When that's merged (and maybe also wordpress-playground#1716), update PHP-WASM dependencies in this PR.

Even after adding _wasm_poll_socket to PHP-WASM, the same two tests are failing with the same WASM errors. ..Oh, I see there are several functions I missed in the error stack trace (from above cause: Error).

  • [x] do_cli
  • [x] dynCall_i
  • [x] invoke_i
  • [ ] php_auto_globals_create_get
  • [ ] php_hash_environment
  • [ ] php_request_startup

I added these to ASYNCIFY_ONLY and recompiled PHP-WASM, but still getting the same WASM errors. I cleared Docker cache with docker builder prune and recompiled again, same result. I noticed playground#1716 was merged, but I'm getting the same result after pull and another recompile.

eliot-akira avatar Sep 11 '24 11:09 eliot-akira

By the way, I'm finding it helpful to use Bun to run functions during development, without having to build the project or run the test suite every time.

In a parent directory, a quick script to try things:

import path from 'node:path'
import getWpNowConfig, { WPNowMode } from './playground-tools/packages/wp-now/src/config'
import { executePHP } from './playground-tools/packages/wp-now/src/execute-php'
import { executeWPCli } from './playground-tools/packages/wp-now/src/execute-wp-cli'

const options = await getWpNowConfig({
  path: path.join(import.meta.dir, 'test'),
  port: 3000,
  reset: true,
})

console.log(
  await executeWPCli(['cli', 'version'])
)

await executePHP(['php', '--version'], options)

await executePHP(['php', `--help`], options)

await executePHP(['php', `-r`, `echo 'hi';`], {
  ...options,
  mode: WPNowMode.INDEX,
})

await executePHP(
  ['php', `-r`, `echo json_encode( scandir('${options.documentRoot}') );`],
  options,
)

This last CLI command throws a different error than in the tests. Maybe the stack trace contains a hint about how to solve it.

  WASM ERROR
  call_indirect to a null table entry (evaluating 'original(...args)') 

29056 |       for (let [x, original] of Object.entries(exports)) {
29057 |         if (typeof original == "function") {
29058 |           ret[x] = (...args) => {
29059 |             Asyncify.exportCallStack.push(x);
29060 |             try {
29061 |               return original(...args);
                             ^
RuntimeError: call_indirect to a null table entry (evaluating 'original(...args)')
      at php.wasm.wasm-function[php_auto_globals_create_get]
      at php.wasm.wasm-function[php_hash_environment]
      at php.wasm.wasm-function[dynCall_i]
      at ~/playground-tools/node_modules/@php-wasm/node/index.js:29061:22
      at ~/playground-tools/node_modules/@php-wasm/universal/index.js:556:18
      at invoke_i (~/playground-tools/node_modules/@php-wasm/node/index.js:29679:14)
      at php.wasm.wasm-function[php_request_startup]
      at php.wasm.wasm-function[dynCall_i]
      at ~/playground-tools/node_modules/@php-wasm/node/index.js:29061:22
      at ~/playground-tools/node_modules/@php-wasm/universal/index.js:556:18
      at invoke_i (~/playground-tools/node_modules/@php-wasm/node/index.js:29679:14)
      at php.wasm.wasm-function[do_cli]
      at php.wasm.wasm-function[dynCall_iii]
      at ~/playground-tools/node_modules/@php-wasm/node/index.js:29061:22
      at ~/playground-tools/node_modules/@php-wasm/universal/index.js:556:18
      at invoke_iii (~/playground-tools/node_modules/@php-wasm/node/index.js:29602:14)
      at php.wasm.wasm-function[run_cli]
      at ~/playground-tools/node_modules/@php-wasm/node/index.js:29061:22
      at ~/playground-tools/node_modules/@php-wasm/universal/index.js:556:18
      at ccall (~/playground-tools/node_modules/@php-wasm/node/index.js:29256:15)
      at ~/playground-tools/node_modules/@php-wasm/universal/index.js:1229:47
      at cli (~/playground-tools/node_modules/@php-wasm/universal/index.js:1220:13)
      at ~/playground-tools/packages/wp-now/src/execute-php.ts:40:13

29856 |   PHPLoader.debug = "debug" in PHPLoader ? PHPLoader.debug : true;
29857 |   if (PHPLoader.debug && typeof Asyncify !== "undefined") {
29858 |     const originalHandleSleep = Asyncify.handleSleep;
29859 |     Asyncify.handleSleep = function(startAsync) {
29860 |       if (!ABORT) {
29861 |         Module["lastAsyncifyStackSource"] = new Error();
                                                    ^
error: Error
      at ~/playground-tools/node_modules/@php-wasm/node/index.js:29861:45
      at php.wasm.wasm-function[php_pollfd_for] (native:1:1)
      at php.wasm.wasm-function[php_network_connect_socket] (native:1:1)
      at php.wasm.wasm-function[php_tcp_sockop_set_option] (native:1:1)
      at php.wasm.wasm-function[php_openssl_sockop_set_option] (native:1:1)
      at php.wasm.wasm-function[_php_stream_set_option] (native:1:1)
      at php.wasm.wasm-function[dynCall_iiiii] (native:1:1)
      at 13211 (native:1:1)
      at ~/playground-tools/node_modules/@php-wasm/node/index.js:33821:11
      at ~/playground-tools/node_modules/@php-wasm/universal/index.js:19:6
      at invoke_iiiii (~/playground-tools/node_modules/@php-wasm/node/index.js:34416:13)
      at php.wasm.wasm-function[_php_stream_xport_create] (native:1:1)
      at php.wasm.wasm-function[zif_stream_socket_client] (native:1:1)
      at php.wasm.wasm-function[ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_HANDLER] (native:1:1)
      at php.wasm.wasm-function[execute_ex] (native:1:1)
      at php.wasm.wasm-function[zend_execute] (native:1:1)
      at php.wasm.wasm-function[zend_execute_scripts] (native:1:1)
      at php.wasm.wasm-function[dynCall_iiiii] (native:1:1)
      at 13211 (native:1:1)
      at ~/playground-tools/node_modules/@php-wasm/node/index.js:33821:11
      at ~/playground-tools/node_modules/@php-wasm/universal/index.js:19:6
      at invoke_iiiii (~/playground-tools/node_modules/@php-wasm/node/index.js:34416:13)
      at php.wasm.wasm-function[php_execute_script] (native:1:1)
      at php.wasm.wasm-function[dynCall_ii] (native:1:1)
      at 13214 (native:1:1)
      at ~/playground-tools/node_modules/@php-wasm/node/index.js:33821:11
      at ~/playground-tools/node_modules/@php-wasm/universal/index.js:19:6
      at invoke_ii (~/playground-tools/node_modules/@php-wasm/node/index.js:34428:13)
      at php.wasm.wasm-function[wasm_sapi_handle_request] (native:1:1)
      at 9847 (native:1:1)
      at ~/playground-tools/node_modules/@php-wasm/node/index.js:33821:11
      at ~/playground-tools/node_modules/@php-wasm/universal/index.js:19:6

Here's the complete list of wasm-functions from above, checked against the Dockerfile for PHP-WASM.

  • [x] _php_stream_set_option
  • [x] _php_stream_xport_create
  • [ ] _wasm_poll_socket
  • [x] do_cli
  • [x] dynCall_i
  • [x] dynCall_ii
  • [x] dynCall_iii
  • [x] dynCall_iiiii
  • [x] execute_ex
  • [x] invoke_i
  • [x] invoke_iii
  • [x] invoke_iiiii
  • [ ] php_auto_globals_create_get
  • [ ] php_hash_environment
  • [ ] php_request_startup
  • [x] php_execute_script
  • [x] php_network_connect_socket
  • [x] php_openssl_sockop_set_option
  • [x] php_pollfd_for
  • [x] php_tcp_sockop_set_option
  • [x] run_cli
  • [x] wasm_sapi_handle_request
  • [x] ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_HANDLER
  • [x] zend_execute
  • [x] zend_execute_scripts
  • [x] zif_stream_socket_client

In my fork of playground, I added:

  • _wasm_poll_socket to EXPORTED_FUNCTIONS
  • missing php_* functions to ASYNCIFY_ONLY (not ASYNCIFY_IMPORTS which is a much shorter list)

For some reason that doesn't solve it.

eliot-akira avatar Sep 11 '24 20:09 eliot-akira

All tests pass when PHP CLI is run in "index" mode.

Other modes (playground, plugin, theme, wordpress) fail with WASM error. That makes me think, maybe the issue is not with missing functions but in the way the PHP instance is set up before calling the CLI.

eliot-akira avatar Sep 11 '24 22:09 eliot-akira

OK, I applied the suggested changes. Thank you for the review. I ported some useful changes from the Studio fork of wp-now, including support for rewrite rules and file not found action; and improvements to php.ini setup and rotate runtime instances with shared init steps.

Getting closer.. All tests passing, except:

I couldn't reproduce the WASM errors you mentioned.

I temporarily "solved" it by forcing PHP CLI to run in index mode. But any other mode throws.

I'll remove that patch so the CI shows the errors again. I'm not sure how to solve this one, as far as I could tell, adding functions to PHP-WASM and recompiling didn't eliminate the error.

eliot-akira avatar Sep 12 '24 17:09 eliot-akira

Thanks for the quick updates! 🙏 I'll check the errors to find a solution. I'll keep you updated.

sejas avatar Sep 12 '24 23:09 sejas

Poke @sejas :)

adamziel avatar Sep 24 '24 12:09 adamziel

I updated Playground dependencies to the newest version 1.0.2.

The WASM error stack trace looks the same as before. I'll try again to solve it, apparently it happens with any wp-now mode other than index.

stderr | src/tests/wp-now.spec.ts > Test starting different modes > validate php comand arguments passed through yargs > php should execute a file
RuntimeError: null function or function signature mismatch
    at php_auto_globals_create_get (wasm://wasm/php.wasm-0372e072:1:6312604)
    ...

stderr | src/tests/wp-now.spec.ts > Test starting different modes > validate php comand arguments passed through yargs > php should execute a file and change php version
RuntimeError: null function or function signature mismatch
    at php_auto_globals_create_get (wasm://wasm/php.wasm-0390d672:1:6582750)
    ...

Strangely, the CI step typecheck is failing for an unrelated file.

image

On my local machine it's passing.

image

eliot-akira avatar Oct 13 '24 15:10 eliot-akira

@eliot-akira , thanks for upgrading to 1.0.2.

I tested it in my laptop. I'm getting the same errors you mentioned, and one more error about compressing (Test starting different modes > startServer > startServer compresses the html file). I need to debug it a bit more.

Currently these are the errors I get when running the wp-now tests npx nx test wp-now:

Full error trace

❯ npx nx test wp-now                             

nx run wp-now:test

RUN v0.31.1 /Users/macbookpro/Documents/projects-m3.nosync/playground-tools/packages/wp-now ✓ src/wp-playground-wordpress/tests/is-valid-wordpress-version.test.ts (1 test) 6ms ✓ src/tests/add-trailing-slash.spec.ts (3 tests) 4ms ✓ src/wp-playground-wordpress/tests/get-plugin-file.spec.ts (3 tests) 3ms ✓ src/tests/github-codespaces.spec.ts (2 tests) 3ms ✓ src/tests/execute-php.spec.ts (4 tests) 441ms stdout | unknown test Downloading wordpress... Downloading sqlite... stdout | unknown test sqlite downloaded. sqlite: 1.056s stdout | unknown test wordpress downloaded. wordpress: 5.044s stderr | src/tests/wp-now.spec.ts > Test starting different modes > validate php comand arguments passed through yargs > php should execute a file RuntimeError: null function or function signature mismatch at php_auto_globals_create_get (wasm://wasm/php.wasm-0372e072:1:6312604) at php_hash_environment (wasm://wasm/php.wasm-0372e072:1:6259481) at dynCall_i (wasm://wasm/php.wasm-0372e072:1:7084092) at ret. (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/node/index.js:92342:22) at t.wasmExports. (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/universal/index.js:556:18) at invoke_i (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/node/index.js:92961:14) at php_request_startup (wasm://wasm/php.wasm-0372e072:1:2610200) at dynCall_i (wasm://wasm/php.wasm-0372e072:1:7084092) at ret. (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/node/index.js:92342:22) at t.wasmExports. (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/universal/index.js:556:18) at invoke_i (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/node/index.js:92961:14) at do_cli (wasm://wasm/php.wasm-0372e072:1:7116695) at dynCall_iii (wasm://wasm/php.wasm-0372e072:1:7083734) at ret. (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/node/index.js:92342:22) at t.wasmExports. (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/universal/index.js:556:18) at invoke_iii (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/node/index.js:92884:14) stderr | src/tests/wp-now.spec.ts > Test starting different modes > validate php comand arguments passed through yargs > php should execute a file and change php version RuntimeError: null function or function signature mismatch at php_auto_globals_create_get (wasm://wasm/php.wasm-0390d672:1:6582750) at null. (wasm://wasm/php.wasm-0390d672:1:8400512) at php_hash_environment (wasm://wasm/php.wasm-0390d672:1:6512206) at null. (wasm://wasm/php.wasm-0390d672:1:8277676) at dynCall_i (wasm://wasm/php.wasm-0390d672:1:7514405) at ret. (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/node/index.js:99769:22) at t.wasmExports. (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/universal/index.js:556:18) at invoke_i (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/node/index.js:100319:14) at php_request_startup (wasm://wasm/php.wasm-0390d672:1:2766633) at null. (wasm://wasm/php.wasm-0390d672:1:8273290) at dynCall_i (wasm://wasm/php.wasm-0390d672:1:7514405) at ret. (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/node/index.js:99769:22) at t.wasmExports. (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/universal/index.js:556:18) at invoke_i (file:///Users/macbookpro/Documents/projects-m3.nosync/playground-tools/node_modules/@php-wasm/node/index.js:100319:14) at do_cli (wasm://wasm/php.wasm-0390d672:1:7549060) at null. (wasm://wasm/php.wasm-0390d672:1:8273601) ❯ src/tests/wp-now.spec.ts (46 tests | 3 failed | 1 skipped) 80778ms ❯ src/tests/wp-now.spec.ts > Test starting different modes > validate php comand arguments passed through yargs > php should execute a file → expected '' to match /8.0/i ❯ src/tests/wp-now.spec.ts > Test starting different modes > validate php comand arguments passed through yargs > php should execute a file and change php version → expected '' to match /7.4/i ❯ src/tests/wp-now.spec.ts > Test starting different modes > startServer > startServer compresses the html file → expected null to be 'gzip' // Object.is equality ⎯⎯⎯⎯⎯⎯⎯ Failed Tests 3 ⎯⎯⎯⎯⎯⎯⎯ FAIL src/tests/wp-now.spec.ts > Test starting different modes > validate php comand arguments passed through yargs > php should execute a file AssertionError: expected '' to match /8.0/i ❯ src/tests/wp-now.spec.ts:664:19 662| process.argv = ['node', 'wp-now', 'php', filePath]; 663| await runCli(); 664| expect(output).toMatch(/8.0/i); | ^ 665| expect(processExitMock).toHaveBeenCalledWith(0); 666| }); ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/3]⎯ FAIL src/tests/wp-now.spec.ts > Test starting different modes > validate php comand arguments passed through yargs > php should execute a file and change php version AssertionError: expected '' to match /7.4/i ❯ src/tests/wp-now.spec.ts:679:19 677| ]; 678| await runCli(); 679| expect(output).toMatch(/7.4/i); | ^ 680| expect(processExitMock).toHaveBeenCalledWith(0); 681| }); ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/3]⎯ FAIL src/tests/wp-now.spec.ts > Test starting different modes > startServer > startServer compresses the html file AssertionError: expected null to be 'gzip' // Object.is equality ❯ src/tests/wp-now.spec.ts:718:48 716| ])('startServer compresses the %s file', async (_, file) => { 717| const req = await fetch(${options.absoluteUrl}${file}); 718| expect(req.headers.get('content-encoding')).toBe('gzip'); | ^ 719| }); 720|

  • Expected - 0
  • Received + 1
  • 'gzip'
  • null ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/3]⎯ Test Files 1 failed | 5 passed (6) Tests 3 failed | 55 passed | 1 skipped (59) Start at 17:04:02 Duration 81.61s (transform 152ms, setup 0ms, collect 1.01s, tests 81.23s, environment 1.68s, prepare 263ms)

——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

NX Ran target test for project wp-now (1m)

✖    1/1 failed
✔    0/1 succeeded [0 read from cache]

Screenshot 2024-10-16 at 17 06 01

What is weird is that in CI it seems to (fail)(https://github.com/WordPress/playground-tools/actions/runs/11314731564/job/31465056405?pr=350) onwordpress-playground-block:typecheck. And in my laptop the typcheck passes correctly.

> nx run wordpress-playground-block:typecheck

Error: packages/wordpress-playground-block/src/components/playground-preview/download-zipped-package.ts(9,2): error TS7006: Parameter 'codeEditorMode' implicitly has an 'any' type.
Warning: run-commands command "tsc -p packages/wordpress-playground-block/tsconfig.lib.json --noEmit" exited with non-zero status code

While in my local machine, those typecheck pass:

Screenshot 2024-10-16 at 17 13 10

sejas avatar Oct 16 '24 16:10 sejas

I've updated executePHP to work only on index mode. I think it's a good solution because users will probably use wp-now php on sites that already exist. Ideally in the future we could remove the modes and just setup the WordPress folders the first time the users starts a site. (https://github.com/WordPress/playground-tools/pull/350/commits/2dbb1a52589a383d8f51a158f803384e8b3fabe7)

I also fixed the tests that were checking if express was compressing files before sending them in the request. (https://github.com/WordPress/playground-tools/pull/350/commits/a73938c241c3b85cfc4693d38a1e8d74d9faf7cc)

Let's see if the nx run wordpress-playground-block:typecheck pass this time 🤞

sejas avatar Oct 16 '24 22:10 sejas

It seems the CI rebases from trunk, that's why we didn't get the error in our local machines. I fixed the typecheck here https://github.com/WordPress/playground-tools/pull/350/commits/123551999a96aeb6b9abf688314b4ce6a937e394

sejas avatar Oct 17 '24 05:10 sejas

Whew, that was a tough one. :smile: Thank you for seeing it through!

eliot-akira avatar Oct 17 '24 11:10 eliot-akira

Thank YOU @eliot-akira for working hard on it 🙏 .

I couldn't publish the release yet, I got some errors in the build process. I created a PR https://github.com/WordPress/playground-tools/pull/359 but I think I also caught a bug in wordpress-playground repo.

sejas avatar Oct 17 '24 11:10 sejas