diff --git a/packages/docs/site/docs/11-architecture/08-browser-concepts.md b/packages/docs/site/docs/11-architecture/08-browser-concepts.md index 1edfd95acb..2420d1264b 100644 --- a/packages/docs/site/docs/11-architecture/08-browser-concepts.md +++ b/packages/docs/site/docs/11-architecture/08-browser-concepts.md @@ -18,5 +18,5 @@ The [`@php-wasm/web`](https://github.com/WordPress/wordpress-playground/blob/tru - [**Browser tab orchestrates everything**](./09-browser-tab-orchestrates-execution.md) – The browser tab is the main program. Closing or reloading it means destroying the entire execution environment. - [**Iframe-based rendering**](./10-browser-iframe-rendering.md) – Every response produced by the PHP server must be rendered in an iframe to avoid reloading the browser tab when the user clicks on a link. -- [**PHP Worker Thread**](./11-browser-php-worker-threads.md) – The PHP server is slow and must run in a worker thread, otherwise handling requests freezes the website UI. +- [**PHP Worker Thread**](./11-browser-php-worker-threads.md) – The PHP server is slow and must run in a web worker, otherwise handling requests freezes the website UI. - [**Service Worker routing**](./12-browser-service-workers.md) – All HTTP requests originating in that iframe must be intercepted by a Service worker and passed on to the PHP worker thread for rendering. diff --git a/packages/docs/site/docs/11-architecture/09-browser-tab-orchestrates-execution.md b/packages/docs/site/docs/11-architecture/09-browser-tab-orchestrates-execution.md index ad5938fa3a..70948b004e 100644 --- a/packages/docs/site/docs/11-architecture/09-browser-tab-orchestrates-execution.md +++ b/packages/docs/site/docs/11-architecture/09-browser-tab-orchestrates-execution.md @@ -24,7 +24,7 @@ Here's what that boot sequence looks like in code: **/app.ts**: ```ts -import { consumeAPI, PHPClient, recommendedWorkerBackend, registerServiceWorker, spawnPHPWorkerThread } from '@php-wasm/web'; +import { consumeAPI, PHPClient, registerServiceWorker, spawnPHPWorkerThread } from '@php-wasm/web'; const workerUrl = '/worker-thread.js'; @@ -32,7 +32,6 @@ export async function startApp() { const phpClient = consumeAPI( await spawnPHPWorkerThread( workerUrl, // Valid Worker script URL - recommendedWorkerBackend, // "webworker" or "iframe", see the docstring { wpVersion: 'latest', phpVersion: '7.4', // Startup options diff --git a/packages/docs/site/docs/11-architecture/11-browser-php-worker-threads.md b/packages/docs/site/docs/11-architecture/11-browser-php-worker-threads.md index d8e935879e..141f966bc7 100644 --- a/packages/docs/site/docs/11-architecture/11-browser-php-worker-threads.md +++ b/packages/docs/site/docs/11-architecture/11-browser-php-worker-threads.md @@ -1,6 +1,6 @@ # PHP Worker Threads -PHP is always ran in a separate thread we'll call a "Worker Thread." This happens to ensure the PHP runtime doesn't slow down the website. +PHP is always ran in a [web worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) to ensure the PHP runtime doesn't slow down the user interface of the main website. Imagine the following code: @@ -11,81 +11,22 @@ Imagine the following code: As soon as you click that button the browser will freeze and you won't be able to type in the input. That's just how browsers work. Whether it's a for loop or a PHP server, running intensive tasks slows down the user interface. -### Initiating the worker thread +### Initiating web workers -Worker threads are separate programs that can process heavy tasks outside of the main application. They must be initiated by the main JavaScript program living in the browser tab. Here's how: +Web workers are separate programs that can process heavy tasks outside of the main application. They must be initiated by the main JavaScript program living in the browser tab. Here's how: ```ts const phpClient = consumeAPI( spawnPHPWorkerThread( - '/worker-thread.js', // Valid Worker script URL - recommendedWorkerBackend // "webworker" or "iframe", see the docstring + '/worker-thread.js' // Valid Worker script URL ) ); await phpClient.isReady(); await phpClient.run({ code: `(spawnPHPWorkerThread('/worker-thread.js', 'webworker')); -``` - -#### `iframe` - -Loads the PHPRequestHandler in a new iframe to avoid crashes in browsers based on Google Chrome. - -The browser will **typically** run an iframe in a separate thread in one of the two cases: - -1. The `iframe-worker.html` is served with the `Origin-Agent-Cluster: ?1` header. If you're running the Apache webserver, this package ships a `.htaccess` that will add the header for you. -2. The `iframe-worker.html` is served from a different origin. For convenience, you could point a second domain name to the same server and directory and use it just for the `iframe-worker.html`. - -Pick your favorite option and make sure to use it for serving the `iframe-worker.html`. - -Example usage: - -**/app.js**: - -```ts -const phpClient = consumeAPI(spawnPHPWorkerThread('/iframe-worker.html?script=/worker-thread.js', 'iframe')); -``` - -**/iframe-worker.html** (Also provided in `@php-wasm/web` package): - -```js - - - - - - - -``` +This can be tedious, which is why Playground provides a convenient [consumeAPI](/api/web/function/consumeAPI) function that abstracts the message exchange and exposes specific functions from the web worker. This is why we can call `phpClient.run` in the example above. diff --git a/packages/php-wasm/web-service-worker/src/initialize-service-worker.ts b/packages/php-wasm/web-service-worker/src/initialize-service-worker.ts index 22c4d79aa5..f417f16298 100644 --- a/packages/php-wasm/web-service-worker/src/initialize-service-worker.ts +++ b/packages/php-wasm/web-service-worker/src/initialize-service-worker.ts @@ -160,7 +160,7 @@ export async function convertFetchEventToPHPRequest(event: FetchEvent) { * what this function uses to broadcast the message. * * @param message The message to broadcast. - * @param scope Target worker thread scope. + * @param scope Target web worker scope. * @returns The request ID to receive the reply. */ export async function broadcastMessageExpectReply(message: any, scope: string) { diff --git a/packages/php-wasm/web/src/lib/index.ts b/packages/php-wasm/web/src/lib/index.ts index 8f665b3dbc..b426a7dbf1 100644 --- a/packages/php-wasm/web/src/lib/index.ts +++ b/packages/php-wasm/web/src/lib/index.ts @@ -8,7 +8,4 @@ export { getPHPLoaderModule } from './get-php-loader-module'; export { registerServiceWorker } from './register-service-worker'; export { parseWorkerStartupOptions } from './worker-thread/parse-startup-options'; -export { - spawnPHPWorkerThread, - recommendedWorkerBackend, -} from './worker-thread/spawn-php-worker-thread'; +export { spawnPHPWorkerThread } from './worker-thread/spawn-php-worker-thread'; 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 102a1305b4..98f480b7da 100644 --- a/packages/php-wasm/web/src/lib/register-service-worker.ts +++ b/packages/php-wasm/web/src/lib/register-service-worker.ts @@ -31,7 +31,7 @@ export async function registerServiceWorker< // the update: await registration.update(); - // Proxy the service worker messages to the worker thread: + // Proxy the service worker messages to the web worker: navigator.serviceWorker.addEventListener( 'message', async function onMessage(event) { 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 f7c4891e23..60ce06b31b 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 @@ -1,42 +1,16 @@ -/** - * Recommended Worker Thread backend. - * It's typically "webworker", but in Firefox it's "iframe" - * because Firefox doesn't support module workers with dynamic imports. - * See https://github.com/mdn/content/issues/24402 - */ -export const recommendedWorkerBackend = (function () { - const isFirefox = - typeof navigator !== 'undefined' && - navigator?.userAgent?.toLowerCase().indexOf('firefox') > -1; - if (isFirefox) { - return 'iframe'; - } else { - return 'webworker'; - } -})(); - /** * Spawns a new Worker Thread. * * @param workerUrl The absolute URL of the worker script. - * @param workerBackend The Worker Thread backend to use. Either 'webworker' or 'iframe'. * @param config * @returns The spawned Worker Thread. */ export async function spawnPHPWorkerThread( workerUrl: string, - workerBackend: 'webworker' | 'iframe' = 'webworker', startupOptions: Record = {} ) { workerUrl = addQueryParams(workerUrl, startupOptions); - - if (workerBackend === 'webworker') { - return new Worker(workerUrl, { type: 'module' }); - } else if (workerBackend === 'iframe') { - return (await createIframe(workerUrl)).contentWindow!; - } else { - throw new Error(`Unknown backendName: ${workerBackend}`); - } + return new Worker(workerUrl, { type: 'module' }); } function addQueryParams( diff --git a/packages/playground/remote/iframe-worker.html b/packages/playground/remote/iframe-worker.html deleted file mode 100644 index a04216afb0..0000000000 --- a/packages/playground/remote/iframe-worker.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/packages/playground/remote/src/lib/boot-playground-remote.ts b/packages/playground/remote/src/lib/boot-playground-remote.ts index 1011be04cf..301acbc96b 100644 --- a/packages/playground/remote/src/lib/boot-playground-remote.ts +++ b/packages/playground/remote/src/lib/boot-playground-remote.ts @@ -7,7 +7,6 @@ import { spawnPHPWorkerThread, exposeAPI, consumeAPI, - recommendedWorkerBackend, } from '@php-wasm/web'; import type { PlaygroundWorkerEndpoint } from './worker-thread'; @@ -21,24 +20,8 @@ const origin = new URL('/', (import.meta || {}).url).origin; // @ts-ignore import moduleWorkerUrl from './worker-thread?worker&url'; -// Hardcoded for now, this file lives in the /public folder -// @ts-ignore -const iframeHtmlUrl = '/iframe-worker.html'; - -export const workerBackend = recommendedWorkerBackend; -export const workerUrl: string = (function () { - switch (workerBackend) { - case 'webworker': - return new URL(moduleWorkerUrl, origin) + ''; - case 'iframe': { - const wasmWorkerUrl = new URL(iframeHtmlUrl, origin); - wasmWorkerUrl.searchParams.set('scriptUrl', moduleWorkerUrl); - return wasmWorkerUrl + ''; - } - default: - throw new Error(`Unknown backend: ${workerBackend}`); - } -})(); + +export const workerUrl: string = new URL(moduleWorkerUrl, origin) + ''; // @ts-ignore import serviceWorkerPath from '../../service-worker.ts?worker&url'; @@ -77,7 +60,7 @@ export async function bootPlaygroundRemote() { LatestSupportedPHPVersion ); const workerApi = consumeAPI( - await spawnPHPWorkerThread(workerUrl, workerBackend, { + await spawnPHPWorkerThread(workerUrl, { wpVersion, phpVersion, persistent: query.has('persistent') ? 'true' : 'false', diff --git a/packages/playground/remote/vite.config.ts b/packages/playground/remote/vite.config.ts index bdeaa545e2..1d30384a22 100644 --- a/packages/playground/remote/vite.config.ts +++ b/packages/playground/remote/vite.config.ts @@ -71,7 +71,6 @@ export default defineConfig({ rollupOptions: { input: { wordpress: path('/remote.html'), - 'iframe-worker': path('/iframe-worker.html'), }, }, },