From ccadc7d0daedda0b59b571e12aade32cf3abaeab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Mon, 19 Aug 2024 22:53:35 +0200 Subject: [PATCH] A boot() method to explicitly initialize the PHP worker (#1669) ## Motivation for the change, related issues Refactors the `remote.html` and `worker-thread.ts` boot flows. * **Before this PR**, both files passed configuration using query arguments and relied on implicit logic surrounding the endpoint class * **After this PR**, both API Endpoint classes expose a `boot()` method that is strongly typed, accepts the configuration values, and explicitly orchestrates all the boot logic when it is called. This work may eventually enable: * A reusable, isomorphic Worker implementation that can be reused in the browser and in a local CLI setup. * Exposing `bootWordPress()` on a worker instance. * Hot-swapping the PHP runtime and WordPress instance (e.g. by killing the current worker and starting a new one). * Spawning new workers, not just PHP class instances, via PHPProcessManager. Related to https://github.com/WordPress/wordpress-playground/issues/1398 ## Follow-up work * Explore spawning multiple workers for handling requests. This might also require: * Exposing the full boot protocol (`bootWordPress()`) on a worker instance instead of the simplified `boot()` method. * Load balancer across all workers handling the same site instance. * An OPFS Emscripten filesystem backend so that each worker can see the changes made by other workers. This is a potential blocker as Emscripten didn't seem to have a good way of doing that a few months ago. ## Testing Instructions (or ideally a Blueprint) * Confirm the tests are all green * Carefully review the changes, point out anything that seems off cc @brandonpayton @bgrgicak --------- Co-authored-by: Brandon Payton --- CHANGELOG.md | 27 +- packages/docs/site/docs/main/changelog.md | 27 +- .../web/src/lib/directory-handle-mount.ts | 10 + packages/php-wasm/web/src/lib/index.ts | 6 +- .../web/src/lib/register-service-worker.ts | 2 +- .../worker-thread/spawn-php-worker-thread.ts | 10 +- packages/playground/client/src/index.ts | 116 +-- .../remote/src/lib/boot-playground-remote.ts | 257 +++---- packages/playground/remote/src/lib/index.ts | 6 +- .../remote/src/lib/opfs/bind-opfs.ts | 71 -- .../playground/remote/src/lib/opfs/types.ts | 28 - .../remote/src/lib/playground-client.ts | 15 +- .../remote/src/lib/worker-thread.ts | 705 ++++++++---------- .../playground/remote/src/lib/worker-utils.ts | 249 ++++--- packages/playground/storage/src/index.ts | 1 + .../playground/storage/src/lib/browser-fs.ts | 45 ++ packages/playground/storage/tsconfig.lib.json | 3 +- .../website/cypress/e2e/query-api.cy.ts | 4 +- .../website/cypress/e2e/website-ui.cy.ts | 4 +- .../mount-markdown-directory-modal/index.tsx | 81 -- .../playground-configuration-group/index.tsx | 36 +- .../reload-with-new-configuration.ts | 9 +- .../start-over-button.tsx | 15 +- .../sync-local-files-button.tsx | 14 +- .../site-manager/add-site-button/index.tsx | 2 +- .../site-manager-sidebar/style.module.css | 4 +- .../src/components/site-view/site-view.tsx | 3 - .../components/toolbar-buttons/reset-site.tsx | 12 +- .../src/github/github-oauth-guard/index.tsx | 3 +- .../src/lib/markdown-directory-handle.ts | 13 - .../playground/website/src/lib/redux-store.ts | 58 +- .../website/src/lib/use-boot-playground.ts | 99 +-- packages/playground/website/src/main.tsx | 12 +- .../playground/wordpress-builds/src/index.ts | 14 +- .../get-sqlite-database-plugin-details.ts | 2 - packages/playground/wordpress/src/boot.ts | 25 +- .../wordpress/src/test/version-detect.spec.ts | 4 +- 37 files changed, 896 insertions(+), 1096 deletions(-) delete mode 100644 packages/playground/remote/src/lib/opfs/bind-opfs.ts delete mode 100644 packages/playground/remote/src/lib/opfs/types.ts create mode 100644 packages/playground/storage/src/lib/browser-fs.ts delete mode 100644 packages/playground/website/src/components/mount-markdown-directory-modal/index.tsx delete mode 100644 packages/playground/website/src/lib/markdown-directory-handle.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 64cfe61c3a..0b300a4389 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,19 +4,19 @@ All notable changes to this project are documented in this file by a CI job that runs on every NPM release. The file follows the [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format. -## [v0.9.30] (2024-08-19) +## [v0.9.30] (2024-08-19) ### Website -- Ask users to report errors if Playground load fails. ([#1686](https://github.com/WordPress/wordpress-playground/pull/1686)) +- Ask users to report errors if Playground load fails. ([#1686](https://github.com/WordPress/wordpress-playground/pull/1686)) ### Bug Fixes -- Avoid Blueprint schema formatting changes by build. ([#1685](https://github.com/WordPress/wordpress-playground/pull/1685)) +- Avoid Blueprint schema formatting changes by build. ([#1685](https://github.com/WordPress/wordpress-playground/pull/1685)) ### Various -- [Website] Improves the messaging around exporting a zip if needed, when connecting to GitHub. ([#1689](https://github.com/WordPress/wordpress-playground/pull/1689)) +- [Website] Improves the messaging around exporting a zip if needed, when connecting to GitHub. ([#1689](https://github.com/WordPress/wordpress-playground/pull/1689)) ### Contributors @@ -24,33 +24,31 @@ The following contributors merged PRs in this release: @brandonpayton @jonathanbossenger - -## [v0.9.29] (2024-08-12) +## [v0.9.29] (2024-08-12) ### Tools -- Add max-len rule. ([#1613](https://github.com/WordPress/wordpress-playground/pull/1613)) +- Add max-len rule. ([#1613](https://github.com/WordPress/wordpress-playground/pull/1613)) ### Experiments - #### GitHub integration -- Add site manager view and sidebar. ([#1661](https://github.com/WordPress/wordpress-playground/pull/1661)) -- Add sites from the site manager. ([#1680](https://github.com/WordPress/wordpress-playground/pull/1680)) +- Add site manager view and sidebar. ([#1661](https://github.com/WordPress/wordpress-playground/pull/1661)) +- Add sites from the site manager. ([#1680](https://github.com/WordPress/wordpress-playground/pull/1680)) ### PHP WebAssembly -- Offline mode end-to-end tests. ([#1648](https://github.com/WordPress/wordpress-playground/pull/1648)) +- Offline mode end-to-end tests. ([#1648](https://github.com/WordPress/wordpress-playground/pull/1648)) ### Website -- Add nice redirects for the new documentation site. ([#1681](https://github.com/WordPress/wordpress-playground/pull/1681)) -- Fix site manager button styles. ([#1676](https://github.com/WordPress/wordpress-playground/pull/1676)) +- Add nice redirects for the new documentation site. ([#1681](https://github.com/WordPress/wordpress-playground/pull/1681)) +- Fix site manager button styles. ([#1676](https://github.com/WordPress/wordpress-playground/pull/1676)) ### Bug Fixes -- Revert "Offline mode end-to-end tests". ([#1673](https://github.com/WordPress/wordpress-playground/pull/1673)) +- Revert "Offline mode end-to-end tests". ([#1673](https://github.com/WordPress/wordpress-playground/pull/1673)) ### Contributors @@ -58,7 +56,6 @@ The following contributors merged PRs in this release: @adamziel @bgrgicak - ## [v0.9.28] (2024-08-05) ### Blueprints diff --git a/packages/docs/site/docs/main/changelog.md b/packages/docs/site/docs/main/changelog.md index 17af18e3f7..8931c662d8 100644 --- a/packages/docs/site/docs/main/changelog.md +++ b/packages/docs/site/docs/main/changelog.md @@ -9,19 +9,19 @@ All notable changes to this project are documented in this file by a CI job that runs on every NPM release. The file follows the [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format. -## [v0.9.30] (2024-08-19) +## [v0.9.30] (2024-08-19) ### Website -- Ask users to report errors if Playground load fails. ([#1686](https://github.com/WordPress/wordpress-playground/pull/1686)) +- Ask users to report errors if Playground load fails. ([#1686](https://github.com/WordPress/wordpress-playground/pull/1686)) ### Bug Fixes -- Avoid Blueprint schema formatting changes by build. ([#1685](https://github.com/WordPress/wordpress-playground/pull/1685)) +- Avoid Blueprint schema formatting changes by build. ([#1685](https://github.com/WordPress/wordpress-playground/pull/1685)) ### Various -- [Website] Improves the messaging around exporting a zip if needed, when connecting to GitHub. ([#1689](https://github.com/WordPress/wordpress-playground/pull/1689)) +- [Website] Improves the messaging around exporting a zip if needed, when connecting to GitHub. ([#1689](https://github.com/WordPress/wordpress-playground/pull/1689)) ### Contributors @@ -29,33 +29,31 @@ The following contributors merged PRs in this release: @brandonpayton @jonathanbossenger - -## [v0.9.29] (2024-08-12) +## [v0.9.29] (2024-08-12) ### Tools -- Add max-len rule. ([#1613](https://github.com/WordPress/wordpress-playground/pull/1613)) +- Add max-len rule. ([#1613](https://github.com/WordPress/wordpress-playground/pull/1613)) ### Experiments - #### GitHub integration -- Add site manager view and sidebar. ([#1661](https://github.com/WordPress/wordpress-playground/pull/1661)) -- Add sites from the site manager. ([#1680](https://github.com/WordPress/wordpress-playground/pull/1680)) +- Add site manager view and sidebar. ([#1661](https://github.com/WordPress/wordpress-playground/pull/1661)) +- Add sites from the site manager. ([#1680](https://github.com/WordPress/wordpress-playground/pull/1680)) ### PHP WebAssembly -- Offline mode end-to-end tests. ([#1648](https://github.com/WordPress/wordpress-playground/pull/1648)) +- Offline mode end-to-end tests. ([#1648](https://github.com/WordPress/wordpress-playground/pull/1648)) ### Website -- Add nice redirects for the new documentation site. ([#1681](https://github.com/WordPress/wordpress-playground/pull/1681)) -- Fix site manager button styles. ([#1676](https://github.com/WordPress/wordpress-playground/pull/1676)) +- Add nice redirects for the new documentation site. ([#1681](https://github.com/WordPress/wordpress-playground/pull/1681)) +- Fix site manager button styles. ([#1676](https://github.com/WordPress/wordpress-playground/pull/1676)) ### Bug Fixes -- Revert "Offline mode end-to-end tests". ([#1673](https://github.com/WordPress/wordpress-playground/pull/1673)) +- Revert "Offline mode end-to-end tests". ([#1673](https://github.com/WordPress/wordpress-playground/pull/1673)) ### Contributors @@ -63,7 +61,6 @@ The following contributors merged PRs in this release: @adamziel @bgrgicak - ## [v0.9.28] (2024-08-05) ### Blueprints diff --git a/packages/php-wasm/web/src/lib/directory-handle-mount.ts b/packages/php-wasm/web/src/lib/directory-handle-mount.ts index 1cc6acdfa1..9f8fba9f5a 100644 --- a/packages/php-wasm/web/src/lib/directory-handle-mount.ts +++ b/packages/php-wasm/web/src/lib/directory-handle-mount.ts @@ -29,6 +29,16 @@ declare global { } } +export type MountDevice = + | { + type: 'opfs'; + path: string; + } + | { + type: 'local-fs'; + handle: FileSystemDirectoryHandle; + }; + export interface MountOptions { initialSync: { direction?: 'opfs-to-memfs' | 'memfs-to-opfs'; diff --git a/packages/php-wasm/web/src/lib/index.ts b/packages/php-wasm/web/src/lib/index.ts index 5a5c898759..af054e52c5 100644 --- a/packages/php-wasm/web/src/lib/index.ts +++ b/packages/php-wasm/web/src/lib/index.ts @@ -4,12 +4,16 @@ export type { LoaderOptions as PHPWebLoaderOptions } from './load-runtime'; export { loadWebRuntime } from './load-runtime'; export { getPHPLoaderModule } from './get-php-loader-module'; -export { registerServiceWorker, setPhpApi } from './register-service-worker'; +export { + registerServiceWorker, + setPhpInstanceUsedByServiceWorker, +} from './register-service-worker'; export { setupPostMessageRelay } from './setup-post-message-relay'; export { spawnPHPWorkerThread } from './worker-thread/spawn-php-worker-thread'; export { createDirectoryHandleMountHandler } from './directory-handle-mount'; export type { + MountDevice, MountOptions, SyncProgress, SyncProgressCallback, diff --git a/packages/php-wasm/web/src/lib/register-service-worker.ts b/packages/php-wasm/web/src/lib/register-service-worker.ts index 9114a912fe..dd6cee85c6 100644 --- a/packages/php-wasm/web/src/lib/register-service-worker.ts +++ b/packages/php-wasm/web/src/lib/register-service-worker.ts @@ -23,7 +23,7 @@ export const phpApiPromise = new Promise((resolve) => { * @param {Client} api The PHP API client. * */ -export function setPhpApi(api: Client) { +export function setPhpInstanceUsedByServiceWorker(api: Client) { if (!api) { throw new PhpWasmError('PHP API client must be a valid client object.'); } diff --git a/packages/php-wasm/web/src/lib/worker-thread/spawn-php-worker-thread.ts b/packages/php-wasm/web/src/lib/worker-thread/spawn-php-worker-thread.ts index 2a5abd30ca..2ced020ea5 100644 --- a/packages/php-wasm/web/src/lib/worker-thread/spawn-php-worker-thread.ts +++ b/packages/php-wasm/web/src/lib/worker-thread/spawn-php-worker-thread.ts @@ -2,13 +2,9 @@ * Spawns a new Worker Thread. * * @param workerUrl The absolute URL of the worker script. - * @param config * @returns The spawned Worker Thread. */ -export async function spawnPHPWorkerThread( - workerUrl: string, - startupOptions: Record = {} -) { +export async function spawnPHPWorkerThread(workerUrl: string) { const worker = new Worker(workerUrl, { type: 'module' }); return new Promise((resolve, reject) => { worker.onerror = (e) => { @@ -20,10 +16,6 @@ export async function spawnPHPWorkerThread( (error as any).filename = e.filename; reject(error); }; - worker.postMessage({ - type: 'startup-options', - startupOptions, - }); // There is no way to know when the worker script has started // executing, so we use a message to signal that. function onStartup(event: { data: string }) { diff --git a/packages/playground/client/src/index.ts b/packages/playground/client/src/index.ts index c63a99bde7..666f9059d8 100644 --- a/packages/playground/client/src/index.ts +++ b/packages/playground/client/src/index.ts @@ -22,7 +22,7 @@ export { SupportedPHPVersionsList, LatestSupportedPHPVersion, } from '@php-wasm/universal'; -export type { PlaygroundClient } from '@wp-playground/remote'; +export type { PlaygroundClient, MountDescriptor } from '@wp-playground/remote'; export { phpVar, phpVars } from '@php-wasm/util'; @@ -34,8 +34,9 @@ import { } from '@wp-playground/blueprints'; import { consumeAPI } from '@php-wasm/web'; import { ProgressTracker } from '@php-wasm/progress'; -import { PlaygroundClient } from '@wp-playground/remote'; +import type { MountDescriptor, PlaygroundClient } from '@wp-playground/remote'; import { collectPhpLogs, logger } from '@php-wasm/logger'; + export interface StartPlaygroundOptions { iframe: HTMLIFrameElement; remoteUrl: string; @@ -57,7 +58,6 @@ export interface StartPlaygroundOptions { * @private */ sapiName?: string; - /** * Called before the blueprint steps are run, * allows the caller to delay the Blueprint execution @@ -67,6 +67,8 @@ export interface StartPlaygroundOptions { */ onBeforeBlueprint?: () => Promise; siteSlug?: string; + mounts?: Array; + shouldInstallWordPress?: boolean; } /** @@ -86,7 +88,8 @@ export async function startPlaygroundWeb({ onClientConnected = () => {}, sapiName, onBeforeBlueprint, - siteSlug, + mounts, + shouldInstallWordPress, }: StartPlaygroundOptions): Promise { assertValidRemote(remoteUrl); allowStorageAccessByUserActivation(iframe); @@ -95,28 +98,46 @@ export async function startPlaygroundWeb({ progressbar: !disableProgressBar, }); progressTracker.setCaption('Preparing WordPress'); + // Set a default blueprint if none is provided. if (!blueprint) { blueprint = { phpExtensionBundles: ['kitchen-sink'], }; } + const compiled = compileBlueprint(blueprint, { progress: progressTracker.stage(0.5), onStepCompleted: onBlueprintStepCompleted, }); - const playground = await doStartPlaygroundWeb( - iframe, - setQueryParams(remoteUrl, { - php: compiled.versions.php, - wp: compiled.versions.wp, - ['sapi-name']: sapiName, - ['php-extension']: compiled.phpExtensions, - ['networking']: compiled.features.networking ? 'yes' : 'no', - 'site-slug': siteSlug, - }), - progressTracker - ); + + await new Promise((resolve) => { + iframe.src = remoteUrl; + iframe.addEventListener('load', resolve, false); + }); + + // Connect the Comlink API client to the remote worker, + // boot the playground, and run the blueprint steps. + const playground = consumeAPI( + iframe.contentWindow!, + iframe.ownerDocument!.defaultView! + ) as PlaygroundClient; + await playground.isConnected(); + progressTracker.pipe(playground); + const downloadPHPandWP = progressTracker.stage(); + await playground.onDownloadProgress(downloadPHPandWP.loadingListener); + await playground.boot({ + mounts, + sapiName, + shouldInstallWordPress, + phpVersion: compiled.versions.php, + wpVersion: compiled.versions.wp, + phpExtensions: compiled.phpExtensions, + withNetworking: compiled.features.networking, + }); + await playground.isReady(); + downloadPHPandWP.finish(); + collectPhpLogs(logger, playground); onClientConnected(playground); @@ -151,39 +172,6 @@ function allowStorageAccessByUserActivation(iframe: HTMLIFrameElement) { } } -/** - * Internal function to connect an iframe to the playground remote. - * - * @param iframe - * @param remoteUrl - * @param progressTracker - * @returns - */ -async function doStartPlaygroundWeb( - iframe: HTMLIFrameElement, - remoteUrl: string, - progressTracker: ProgressTracker -) { - await new Promise((resolve) => { - iframe.src = remoteUrl; - iframe.addEventListener('load', resolve, false); - }); - - // Connect the Comlink client and wait until the - // playground is ready. - const playground = consumeAPI( - iframe.contentWindow!, - iframe.ownerDocument!.defaultView! - ) as PlaygroundClient; - await playground.isConnected(); - progressTracker.pipe(playground); - const downloadPHPandWP = progressTracker.stage(); - await playground.onDownloadProgress(downloadPHPandWP.loadingListener); - await playground.isReady(); - downloadPHPandWP.finish(); - return playground; -} - const officialRemoteOrigin = 'https://playground.wordpress.net'; function assertValidRemote(remoteHtmlUrl: string) { const url = new URL(remoteHtmlUrl, officialRemoteOrigin); @@ -215,33 +203,3 @@ function setQueryParams(url: string, params: Record) { urlObject.search = qs.toString(); return urlObject.toString(); } - -/** - * @deprecated Use `startPlayground` instead. - * - * @param iframe Any iframe with Playground's remote.html loaded. - * @param options Optional. If `loadRemote` is set, the iframe's `src` will be set to that URL. - * In other words, use this option if your iframe doesn't have - * remote.html already - * loaded. - */ -export async function connectPlayground( - iframe: HTMLIFrameElement, - options?: { loadRemote?: string } -): Promise { - logger.warn( - '`connectPlayground` is deprecated and will be removed. Use `startPlayground` instead.' - ); - if (options?.loadRemote) { - return startPlaygroundWeb({ - iframe, - remoteUrl: options.loadRemote, - }); - } - const client = consumeAPI( - iframe.contentWindow!, - iframe.ownerDocument!.defaultView! - ) as PlaygroundClient; - await client.isConnected(); - return client; -} diff --git a/packages/playground/remote/src/lib/boot-playground-remote.ts b/packages/playground/remote/src/lib/boot-playground-remote.ts index f573607279..02ca085a50 100644 --- a/packages/playground/remote/src/lib/boot-playground-remote.ts +++ b/packages/playground/remote/src/lib/boot-playground-remote.ts @@ -1,11 +1,7 @@ -import { - LatestSupportedPHPVersion, - MessageListener, - SupportedPHPExtensionsList, -} from '@php-wasm/universal'; +import { MessageListener } from '@php-wasm/universal'; import { registerServiceWorker, - setPhpApi, + setPhpInstanceUsedByServiceWorker, spawnPHPWorkerThread, exposeAPI, consumeAPI, @@ -13,7 +9,12 @@ import { SyncProgressCallback, } from '@php-wasm/web'; -import type { PlaygroundWorkerEndpoint } from './worker-thread'; +import type { + PlaygroundWorkerEndpoint, + WorkerBootOptions, + MountDescriptor, +} from './worker-thread'; +export type { MountDescriptor, WorkerBootOptions }; import type { WebClientMixin } from './playground-client'; import ProgressBar, { ProgressBarOptions } from './progress-bar'; @@ -29,8 +30,6 @@ export const workerUrl: string = new URL(moduleWorkerUrl, origin) + ''; // @ts-ignore import serviceWorkerPath from '../../service-worker.ts?worker&url'; -import { LatestSupportedWordPressVersion } from '@wp-playground/wordpress-builds'; -import type { BindOpfsOptions } from './opfs/bind-opfs'; import { FilesystemOperation } from '@php-wasm/fs-journal'; import { setupFetchNetworkTransport } from './setup-fetch-network-transport'; export const serviceWorkerUrl = new URL(serviceWorkerPath, origin); @@ -58,55 +57,30 @@ export async function bootPlaygroundRemote() { document.body.prepend(bar.element); } - const wpVersion = parseVersion( - query.get('wp'), - LatestSupportedWordPressVersion - ); - const phpVersion = parseVersion( - query.get('php'), - LatestSupportedPHPVersion - ); - const phpExtensions = parseList( - query.getAll('php-extension'), - SupportedPHPExtensionsList - ); - const withNetworking = query.get('networking') === 'yes'; - const sapiName = query.get('sapi-name') || undefined; - const scope = Math.random().toFixed(16); await registerServiceWorker(scope, serviceWorkerUrl + ''); - const phpApi = consumeAPI( - await spawnPHPWorkerThread(workerUrl, { - wpVersion, - phpVersion, - ['php-extension']: phpExtensions, - networking: withNetworking ? 'yes' : 'no', - storage: query.get('storage') || '', - ...(sapiName ? { sapiName } : {}), - 'site-slug': query.get('site-slug') || 'wordpress', - scope, - }) + const phpWorkerApi = consumeAPI( + await spawnPHPWorkerThread(workerUrl) ); - // Set PHP API in the service worker - setPhpApi(phpApi); + setPhpInstanceUsedByServiceWorker(phpWorkerApi); const wpFrame = document.querySelector('#wp') as HTMLIFrameElement; - const webApi: WebClientMixin = { + const phpRemoteApi: WebClientMixin = { async onDownloadProgress(fn) { - return phpApi.onDownloadProgress(fn); + return phpWorkerApi.onDownloadProgress(fn); }, async journalFSEvents(root: string, callback) { - return phpApi.journalFSEvents(root, callback); + return phpWorkerApi.journalFSEvents(root, callback); }, async replayFSJournal(events: FilesystemOperation[]) { - return phpApi.replayFSJournal(events); + return phpWorkerApi.replayFSJournal(events); }, async addEventListener(event, listener) { - return await phpApi.addEventListener(event, listener); + return await phpWorkerApi.addEventListener(event, listener); }, async removeEventListener(event, listener) { - return await phpApi.removeEventListener(event, listener); + return await phpWorkerApi.removeEventListener(event, listener); }, async setProgress(options: ProgressBarOptions) { if (!bar) { @@ -191,19 +165,30 @@ export async function bootPlaygroundRemote() { * @returns */ async onMessage(callback: MessageListener) { - return await phpApi.onMessage(callback); + return await phpWorkerApi.onMessage(callback); }, + /** * Ditto for this function. * @see onMessage * @param callback * @returns */ - async bindOpfs( - options: BindOpfsOptions, + async mountOpfs( + options: MountDescriptor, onProgress?: SyncProgressCallback ) { - return await phpApi.bindOpfs(options, onProgress); + return await phpWorkerApi.mountOpfs(options, onProgress); + }, + + /** + * Ditto for this function. + * @see onMessage + * @param mountpoint + * @returns + */ + async unmountOpfs(mountpoint: string) { + return await phpWorkerApi.unmountOpfs(mountpoint); }, /** @@ -211,7 +196,7 @@ export async function bootPlaygroundRemote() { * @see backfillStaticFilesRemovedFromMinifiedBuild in the worker-thread.ts */ async backfillStaticFilesRemovedFromMinifiedBuild() { - await phpApi.backfillStaticFilesRemovedFromMinifiedBuild(); + await phpWorkerApi.backfillStaticFilesRemovedFromMinifiedBuild(); }, /** @@ -219,81 +204,90 @@ export async function bootPlaygroundRemote() { * available in the request cache. */ async hasCachedStaticFilesRemovedFromMinifiedBuild() { - return await phpApi.hasCachedStaticFilesRemovedFromMinifiedBuild(); + return await phpWorkerApi.hasCachedStaticFilesRemovedFromMinifiedBuild(); + }, + + async boot(options) { + await phpWorkerApi.boot({ + ...options, + scope, + }); + + try { + await phpWorkerApi.isReady(); + + setupPostMessageRelay( + wpFrame, + getOrigin((await playground.absoluteUrl)!) + ); + + if (options.withNetworking) { + await setupFetchNetworkTransport(phpWorkerApi); + } + + setAPIReady(); + } catch (e) { + setAPIError(e as Error); + throw e; + } + + /** + * When we're running WordPress from a minified bundle, we're missing some static assets. + * The section below backfills them if needed. It doesn't do anything if the assets are already + * in place, or when WordPress is loaded from a non-minified bundle. + * + * Minified bundles are shipped without most static assets to reduce the bundle size and + * the loading time. When WordPress loads for the first time, the browser parses all the + *