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

使用 WebAssembly,完全在浏览器中运行由 PHP 提供支持的完整 WordPress

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

当您第一次看到 WordPress Playground 时,它看起来像是一个普通的网站,可能只是色彩鲜艳的背景。千变万化您实际看到的是一个直接在浏览器中运行的整个 WordPress 技术栈,包括 PHP 和数据库。

在这篇博文中,WordPress Playground 负责人 Adam Zieli 监控)和 Thomas Nattestad(V8 产品经理)探索了以下内容:

  • WordPress Playground 如何为 WordPress 开发者提供帮助。
  • 其后台运作方式。
  • 这对 WordPress 的未来意味着什么。

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

您可以免费使用和自定义嵌入在 playground.wordpress.net 中的 WordPress。没有需要付费的云基础架构和支持,因为网站完全位于您的浏览器内,任何人都无法访问它。这也是临时性的。该网页一旦刷新,它就会消失。您可以根据需要获取任意数量的网站,以便进行原型设计、试用插件以及快速探索各种想法。

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

phpinfo 页面

WordPress Playground 是一种全新的 WordPress 使用方式。不过,只有将 WordPress Playground 加入您的应用中,它才能充分发挥它的作用。简单的方法是将 WordPress Playground 嵌入到 <iframe> 中,并使用查询参数 API 对其进行配置。这就是官方展示的作用。例如,当您选择 Pendant themeCoblocks 插件时,嵌入式 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。构建 vanilla 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 构建在浏览器中并不是很有用。作为服务器软件,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 附带了原生 SQLite 驱动程序的 PHP 版本,并依赖于 SQLite。

但 WordPress 如何才能在不同的数据库上运行呢?

在后台,官方 SQLite 数据库集成插件会拦截所有 MySQL 查询,并以 SQLite 方言重写这些查询。2.0 版附带支持 WordPress Playground 的全新翻译层,它可让 SQLite 上的 WordPress 通过 99% 的 WordPress 单元测试套件的测试。

Web 服务器位于浏览器内

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

流程图,首先是一个指向资源 wp-admin 的 iframe,对它们的调用被 Service Worker 拦截,在工作器线程中呈现,并最终被浏览器内的服务器转换为 WordPress 响应。

通过 WebSocket 支持网络

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

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

WordPress 可在更多地方使用,不仅仅是浏览器

由于 WordPress 现在可在 WebAssembly 上运行,因此您也可以在 Node.js 服务器中运行它,因为 WordPress 需要使用相同的 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 联系。