close
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
slug: /developers/architecture/browser-concepts
---

# ServiceWorker と Worker Threads を使用してブラウザで PHP アプリを実行する

<!--
# Running PHP apps in the browser with ServiceWorkers and Worker Threads
-->

大まかに言うと、WordPress Playground は Web ブラウザー内で次のように動作します。

<!--
On a high level, WordPress Playground works in web browsers as follows:
-->

- playground.wordpress.net の `index.html` ファイルは、`<iframe src="/remote.html">` を介して `remote.html` ファイルを読み込みます。
- `remote.html` は Worker スレッドと Service Worker を起動し、ダウンロードの進捗情報を返します。
- Worker スレッドは PHP を起動し、SQLite で動作するようにパッチされた WordPress をファイルシステムに設定します。
- Service Worker はすべての HTTP リクエストを傍受し、Worker スレッドに転送し始めます。
- `remote.html` は `<iframe src="/index.php">` を作成し、Service Worker は `index.php` のリクエストを Worker スレッドに転送し、そこで WordPress のホームページがレンダリングされます。

<!--
- The `index.html` file on playground.wordpress.net loads the `remote.html` file via an `<iframe src="/remote.html">`.
- `remote.html` starts a Worker Thread and a ServiceWorker and sends back the download progress information.
- The Worker Thread starts PHP and populates the filesystem with a WordPress patched to run on SQLite.
- The ServiceWorker starts intercepting all HTTP requests and forwarding them to the Worker Thread.
- `remote.html` creates an `<iframe src="/index.php">`, and the Service Worker forwards the `index.php` request to the Worker Thread where the WordPress homepage is rendered.
-->

視覚的には次のようになります。

<!--
Visually, it looks like this:
-->

![Architecture overview](@site/static/img/architecture-overview.webp)

## 高レベルのアイデア

<!--
## High-level ideas
-->

[`@php-wasm/web`](https://github.com/WordPress/wordpress-playground/blob/trunk/packages/php-wasm/web/) は、次のアイデアに基づいて構築されています。

<!--
The [`@php-wasm/web`](https://github.com/WordPress/wordpress-playground/blob/trunk/packages/php-wasm/web/) is built on top of the following ideas:
-->

- [**ブラウザタブがすべてをオーケストレーション**](/developers/architecture/browser-tab-orchestrates-execution) – ブラウザタブがメインプログラムです。タブを閉じたりリロードしたりすると、実行環境全体が破壊されます。
- [**iframeベースのレンダリング**](/developers/architecture/browser-iframe-rendering) – PHPサーバーが生成するすべてのレスポンスはiframeでレンダリングする必要があります。これにより、ユーザーがリンクをクリックしてもブラウザタブがリロードされるのを防ぎます。
- [**PHP ワーカースレッド**](/developers/architecture/browser-php-worker-threads) – PHPサーバーは処理が遅いため、Webワーカーで実行する必要があります。そうしないと、リクエスト処理中にウェブサイトのUIがフリーズしてしまいます。
- [**サービス ワーカー ルーティング**](/developers/architecture/browser-service-workers) – iframe内で発生するすべてのHTTPリクエストはService Workerによって傍受され、レンダリングのためにPHPワーカーに渡されます。

<!--
- [**Browser tab orchestrates everything**](/developers/architecture/browser-tab-orchestrates-execution) – The browser tab is the main program. Closing or reloading it means destroying the entire execution environment.
- [**Iframe-based rendering**](/developers/architecture/browser-iframe-rendering) – 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**](/developers/architecture/browser-php-worker-threads) – The PHP server is slow and must run in a web worker, otherwise handling requests freezes the website UI.
- [**Service Worker routing**](/developers/architecture/browser-service-workers) – All HTTP requests originating in that iframe must be intercepted by a Service worker and passed on to the PHP worker thread for rendering.
-->
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
slug: /developers/architecture/browser-tab-orchestrates-execution
---

# ブラウザタブが実行を調整します

<!--
# Browser tab orchestrates the execution
-->

メインの`index.html`はアプリケーション全体をまとめる役割を果たします。すべての同時プロセスを起動し、PHPレスポンスを表示します。アプリケーションはメインの`index.html`が存在する限り有効です。

<!--
The main `index.html` ties the entire application together. It starts all the concurrent processes and displays the PHP responses. The app only lives as long as the main `index.html`.
-->

残りのドキュメントを読む際には、この点に留意してください。この時点では明らかなように思えるかもしれませんが、後々分かりにくくなる可能性があります。このパッケージは、Web Worker、Service Worker、そして将来的には Shared Worker を使用して、ブラウザタブの外でコードを実行します。これらの Worker の一部は、`index.html` を含むブラウザタブが閉じられた後も実行され続ける可能性があります。

<!--
Keep this point in mind as you read through the rest of the docs. At this point it may seem obvious, by the lines may get blurry later on. This package runs code outside of the browser tab using Web Workers, Service Workers, and, in the future, Shared Workers. Some of these workers may keep running even after the browser tab with `index.html` is closed.
-->

## ブートシーケンス

<!--
## Boot sequence
-->

最小限のアプリのブート シーケンスは次のようになります。

<!--
Here's what a boot sequence for a minimal app looks like:
-->

![The boot sequence](@site/static/img/boot-sequence.webp)

メインアプリは、iframe、サービスワーカー、そしてワーカースレッドを起動します。メインアプリはPHPスタックを直接使用していないことに注意してください。すべてワーカースレッドで処理されます。

<!--
The main app initiates the Iframe, the Service Worker, and the Worker Thread. Note how the main app doesn't use the PHP stack directly – it's all handled in the Worker Thread.
-->

ブート シーケンスをコードで表すと次のようになります。

<!--
Here's what that boot sequence looks like in code:
-->

**/index.html**:

```js
<script src="/app.ts"></script>
<iframe id="my-app"></iframe>
```

**/app.ts**:

```ts
import { consumeAPI, PHPClient, registerServiceWorker, spawnPHPWorkerThread } from '@php-wasm/web';

const workerUrl = '/worker-thread.js';

export async function startApp() {
const phpClient = consumeAPI<PlaygroundWorkerEndpoint>(
await spawnPHPWorkerThread(
workerUrl, // Valid Worker script URL
{
wpVersion: 'latest',
phpVersion: '8.3', // Startup options
}
)
);

// Await the two-way communication channel
await phpClient.isReady();

// Must point to a valid Service Worker script:
await registerServiceWorker(
phpClient,
'default', // PHP instance scope, keep reading to learn more.
'/sw.js', // Valid Service Worker script URL.
'1' // Service worker version, used for reloading the script.
);

// Create a few PHP files to browse:
await workerThread.writeFile('/index.php', '<a href="page.php">Go to page.php</a>');
await workerThread.writeFile('/page.php', '<?php echo "Hello from PHP!"; ?>');

// Navigate to index.php:
document.getElementById('my-app').src = playground.pathToInternalUrl('/index.php');
}
startApp();
```

これらすべての要素がどのように組み合わさるのかを学ぶために読み続けてください。

<!--
Keep reading to learn how all these pieces fit together.
-->

### データフロー

<!--
### Data flow
-->

iframe が同じドメインのリクエストを発行するたびに、次のことが起こります。

<!--
Here's what happens whenever the iframe issues a same-domain request:
-->

![The data flow](@site/static/img/data-flow.webp)

ステップごとの内訳:

<!--
A step-by-step breakdown:
-->

1. リクエストはサービスワーカーによってインターセプトされます。
2. サービスワーカーはリクエストをワーカースレッドに渡します。
3. ワーカースレッドはリクエストをレスポンスに変換するために `PHP.request` を呼び出します。
4. ワーカースレッドはレスポンスをサービスワーカーに渡します。
5. サービスワーカーはブラウザにレスポンスを提供します。

<!--
1. The request is intercepted by the Service Worker
2. The Service Worker passes it to the Worker Thread
3. The Worker Thread calls `PHP.request` to convert that request to a response
4. The Worker Thread passes the response to the Service Worker
5. The Service Worker provides the browser with a response
-->

この時点で、ユーザーがリンクをクリックしてリクエストがトリガーされた場合、ブラウザは PHPRequestHandler の応答を iframe 内にレンダリングします。

<!--
At this point, if the request was triggered by user clicking on a link, the browser will render PHPRequestHandler's response inside the iframe.
-->