使用 WordPress Playground 和 WebAssembly 打造浏览器内的 WordPress 体验

完全由 PHP 驱动的 WordPress,仅在浏览器中使用 WebAssembly 运行

Adam Zieliński
Adam Zieliński
Thomas Nattestad
Thomas Nattestad

初次看到 WordPress Playground 时,它看起来就像一个普通的网站,除了色彩鲜艳的背景之外。完全不是。您实际上看到的是整个 WordPress 技术栈,包括 PHP 和数据库,这些内容直接在浏览器中运行。

在本文中,Adam Zieliński(WordPress Playground 主管)和 Thomas Nattestad(V8 产品经理)将探讨以下内容:

  • WordPress Playground 如何帮助 WordPress 开发者。
  • 其后台工作原理。
  • 这对 WordPress 的未来意味着什么。

无需安装即可使用 WordPress,将其嵌入到您的应用中,甚至可以使用 JavaScript 控制它

您可以免费使用和自定义在 playground.wordpress.net 上嵌入的 WordPress。您无需支付云基础架构和支持费用,因为该网站完全位于您的浏览器中,任何其他人也无法访问。这种情况也是暂时的。刷新页面后,该图标就会消失。您可以创建任意数量的此类网站,以便构建原型、试用插件和快速探索想法。

您甚至可以使用内置的 PHP 和 WordPress 版本切换器在不同的环境中测试代码:

phpinfo 页面。

WordPress Playground 是一种全新的 WordPress 使用方式。不过,只有将其添加到应用中,才能充分发挥其强大功能。最简单的方法是将 WordPress Playground 嵌入到 <iframe> 中,然后使用查询参数 API 对其进行配置。官方展示平台就是为此而生。例如,如果您选择 Pendant 主题Coblocks 插件,嵌入的 iframe 会更新为指向 https://playground.wordpress.net/?theme=pendant&plugin=coblocks

WordPress Playground 展示。

iframe 是一种简单的入门方式,但也仅限于基本配置选项。如果您需要的功能超出上述范围,可以使用另一个功能更强大的 API。

WordPress Playground JavaScript 客户端可让您完全控制嵌入的网站

您可以使用通过 @wp-playground/client npm 软件包提供的完整 API 来控制整个 WordPress 网站,包括文件系统和 PHP。以下示例展示了如何使用它 - 如需查看更多示例,请参阅互动式教程

import {
  connectPlayground,
  login,
  connectPlayground,
} from '@wp-playground/client';

const client = await connectPlayground(
  document.getElementById('wp'), // An iframe
  { loadRemote: 'https://playground.wordpress.net/remote.html' },
);
await client.isReady();

// Login the user as admin and go to the post editor:
await login(client, 'admin', 'password');
await client.goTo('/wp-admin/post-new.php');

// Run arbitrary PHP code:
await client.run({ code: '<?php echo "Hi!"; ?>' });

// Install a plugin:
const plugin = await fetchZipFile();
await installPlugin(client, plugin);

即使没有 WordPress,也能使用 WebAssembly PHP

WordPress Playground 不是单体应用。WebAssembly PHP 是独立于 WordPress 发布的,您也可以单独使用它。对于 Web,您可以使用针对较小软件包大小进行了优化的 @php-wasm/web npm 软件包;在 Node.js 中,您可以依赖于 @php-wasm/node,它提供了更多 PHP 扩展。Adam 使用了前者在 此 WP_HTML_Tag_Processor 教程中添加了互动 PHP 代码段。下面是该功能的使用预览:

import { PHP } from '@php-wasm/web';
const php = await PHP.load('8.0', {
  requestHandler: {
    documentRoot: '/www',
  },
});

// Create and run a script directly
php.mkdirTree('/www');
php.writeFile('/www/index.php', `<?php echo "Hello " . $_POST['name']; ?>`);
php.run({ scriptPath: '/www/index.php' });

// Or use the familiar HTTP concepts:
const response = php.request({
  method: 'POST',
  relativeUrl: '/index.php',
  data: { name: 'John' },
});
console.log(response.text); // Hello John

此时,您一定在想:“这究竟是怎么运作的?”这个问题问得好! 我们来深入了解一下内部机制,找出原因。系好安全带!

底层包含 WebAssembly PHP、SQL 转换器和浏览器内服务器

PHP 作为 WebAssembly 二进制文件运行

PHP 不仅可直接在浏览器中运行,WordPress Playground 开发了一个专用流水线,用于使用 EmscriptenPHP 解释器构建为 WebAssembly。构建原生 PHP 并不复杂,只需调整此处的函数签名强制使用此处的配置变量,并应用一些小补丁即可。您可以按以下步骤自行构建:

git clone https://github.com/WordPress/wordpress-playground
cd wordpress-playground && npm install
# Below, you can replace "8.2" with any other valid PHP version number.
npm run recompile:php:web:8.2

不过,纯 PHP build 在浏览器中用处不大。作为服务器软件,PHP 没有用于传递请求正文、上传文件或填充 php://stdin 流的 JavaScript API。WordPress Playground 不得不从头开始构建一个。WebAssembly 二进制文件附带一个使用 C 语言编写的专用 PHP API 模块,以及一个公开 writeFile()run() 等方法的 JavaScript PHP 类

由于每个 PHP 版本都只是一个静态 .wasm 文件,因此 PHP 版本切换器实际上非常简单。它只是告诉浏览器下载 php_7_3.wasm,而不是 php_8_2.wasm

数据库支持 SQL 转换层

WordPress 需要 MySQL。不过,您无法在浏览器中运行 WebAssembly 版本的 MySQL。因此,WordPress Playground 会将 PHP 与原生 SQLite 驱动程序一起提供,并依赖于 SQLite。

但 WordPress 如何在其他数据库上运行?

在后台,官方 SQLite 数据库集成插件会拦截所有 MySQL 查询,并将其重写为 SQLite 方言。2.0 版提供了一个新的 WordPress Playground 感知型转换层,让 WordPress on SQLite 能够通过 99% 的 WordPress 单元测试套件。

Web 服务器位于浏览器内

在常规 WordPress 中,点击某个链接(例如博客)会向远程后端发起 HTTP 请求,以提取 blog 页面。不过,WordPress Playground 没有远程后端。它有一个 Service Worker,用于拦截所有传出请求并将其传递给在单独的 Web Worker 中运行的浏览器内 PHP 实例。

流程图,从指向资源 wp-admin 的 iframe 开始,对该资源的调用会被 Service Worker 拦截,在 worker 线程中呈现,并最终由浏览器内服务器转换为 WordPress 响应。

支持通过 WebSocket 进行网络连接

在网络方面,WebAssembly 程序仅限于调用 JavaScript API。这项功能是一项安全功能,但也带来了挑战。如何使用 JavaScript 中提供的高级异步 API 支持 PHP 使用的低级同步网络代码?

对于 WordPress Playground,答案涉及将 WebSocket 转换为 TCP 套接字代理、Asyncify 以及修补 php_select 等深层 PHP 内部结构。这项工作很复杂,但回报丰厚。以 Node.js 为目标平台的 PHP build 可以请求 Web API、安装 Composer 软件包,甚至可以连接到 MySQL 服务器。

WordPress 的适用范围比浏览器更广

由于 WordPress 现在可以在 WebAssembly 上运行,因此您也可以在 Node.js 服务器中运行它,因为它们使用的是相同的 V8 引擎!当然,使用 StackBlitz,您还可以在浏览器中直接运行 Node.js,这意味着您可以运行编译为 WebAssembly 的 WordPress 和 PHP,并在 Node.js 中执行,而 Node.js 也编译为 WebAssembly,在浏览器中运行。WebAssembly 在无服务器领域也越来越受欢迎,未来也可能会在该基础架构上运行。

未来,我们或许能推出无需设置、互动性强且协作性高的 WordPress 应用

假设您可以直接跳转到代码编辑器,在完成所有设置后,即可立即开始构建。您甚至可以分享一个简单的链接,并发起多人协同编辑会话,例如在 Google 文档中。完成后,只需点击一下,即可将您的作品无缝部署到各种托管服务中,而无需在本地安装任何内容!

这只是其中的一小部分!我们可能会看到互动式教程、实时插件演示、预演网站、边缘服务器上的去中心化 WordPress,甚至在手机上构建插件。

未来充满希望,您可以成为其中的一员!您的想法和贡献是 WordPress Playground 的生命之源。访问 GitHub 代码库,在 #meta-playground WordPress.org Slack 频道中与我们交流,并随时通过 adam@adamziel.com 与 Adam 联系。