Skip to main content

Isomorphism

https://github.com/WordPress/wordpress-playground/pull/214

Description

Generalizes Playground Blueprints from working with just the in-browser Playground API client to working:

  • On the web and in Node.js
  • With a local Playground object
  • With a remote Playground client

With this PR applied, all of the following login() calls are valid:

// In the browser
const phpInSameThread = await WebPHP.load('7.4');
// unzip WordPress in /wordpress
await login(phpInSameThread);

const phpInWorker = await consumeAPI(playgroundIframe);
await login(phpInWorker);
// In node.js
const phpInSameThread = await NodePHP.load('7.4');
phpInSameThread.mount('/wordpress', '/wordpress');
await login(phpInSameThread);
// ^ @TODO: Still fails unless you provide a DOMParser polyfill

This opens the door to using Blueprints in Node.js tools.

Implementation

Blueprint were initially implemented as a part of the browser API client in @wp-playground/client. This PR decouples them into an isomorphic @wp-playground/blueprints package that depends on @php-wasm/universal which is also isomorphic.

In other words, step handlers such as login(playground) used to require a PlaygroundClient instance, but now they can work with a UniversalPHP instance defined as follows:

type IsomorphicLocalPHP = {
/* ... PHP methods ... */
};
// Remote<T> means every method of T now returns a promise
type IsomorphicRemotePHP = Remote<IsomorphicLocalPHP>;
type UniversalPHP = IsomorphicLocalPHP | IsomorphicRemotePHP;

UniversalPHP is a type, not a class. It's a common core of all PHP implementations in other packages and provides methods like run(), request(), and writeFile(). @php-wasm/universal also provides a reference implementation of UniversalPHP called BasePHP.

BasePHP cannot be used directly. Instead, platform-specific packages @php-wasm/web and @php-wasm/node provide platform-specific implementations. The former exports WebPHP, which loads files using fetch(), and the latter exports NodePHP, which reads data directly from the host filesystem. Both implement the UniversalPHP interface and can be used with any Blueprint step.

Other notes

  • @php-wasm/universal, @wp-playground/client, and @wp-playground/blueprints are published as isomorphic ESM/CJS packages. @php-wasm/node is published as CJS only for now.

Follow-up work

  • @wp-playground/blueprints will need to be smart about providing a Node.js polyfill for new DOMParser() and fetch().