Interactivity API 在底层是如何工作的?

它有三个主要组件:

为什么选择 Preact 来构建指令系统?为什么不使用 React 或其他 JavaScript 框架?

在前端(这是 Interactivity API 的重点)的上下文中,Preact 相比 React 和其他 JavaScript 框架(如 Vue、Svelte 或 Solid)具有许多优势:

  • 它很小:8kB,包括 hooks 和 signals。
  • 它开箱即用提供了 DOM 差异比较功能。
  • 通过其 Option Hooks,它具有极高的可扩展性。他们利用这种扩展性来实现 hooks (preact/hooks)、与 React 的兼容性 (preact/compat) 以及他们的 signals (@preact/signals)。基本上,除了 DOM 差异比较算法之外的所有内容。
  • 其核心团队非常优秀且乐于助人。他们也致力于增强这种“基于岛屿”的 Preact 用法。

Gutenberg 会因为 Interactivity API 使用 Preact 而从 React 迁移到 Preact 吗?

不会。目前,没有进行该过渡的计划。作为完全交互式应用程序,编辑器的需求和优势截然不同。Preact 确实有一个 @preact/compat 包,可实现与 React 生态系统的完全兼容,许多大型 Web 应用程序都在使用它。然而,在区块编辑器中使用 Preact 不会像在 Interactivity API 前端那样带来优势。

除了使用指令外,还考虑了哪些方法?

考虑了许多替代方法。以下是其中一些方法的简要总结:

React 和其他 JavaScript 框架

首先考虑了 React,因为 Gutenberg 开发人员对它很熟悉。其他流行的 JS 框架,如 Svelte、Vue.js 或 Angular 也被考虑在内,但它们(包括 React)都不利于 PHP 或与 WordPress 挂钩或国际化不兼容。

Alpine.js

Alpine.js 是一个很好的框架,它启发了 Interactivity API 中的许多功能。但是,它不支持其 指令 的服务端渲染,拥有一个专门为 WordPress 区块定制的类似系统有许多好处。

出于众多原因,选择了 Preact 而不是 Alpine.js。它的体积更小,性能更好(特别是添加了 signals 之后),并且自定义指令是使用 Preact 的声明式语法和工具(hooks、signals)编写的。与 Alpine.js 相比,Preact 经过更充分的实战测试,拥有更大的社区。此外,它与 React 兼容(用于共享从编辑器渲染的客户端组件),并提供开箱即用的最快的 DOM 差异比较算法,包括 UI 状态保留。

此外,由于 Preact 在后台运行,Interactivity API 管理“最后一层”,以便更好地适应 WordPress 的需求。例如,不允许在指令内使用 JavaScript 表达式,以避免安全风险并确保符合严格的安全策略,所有 WordPress 指令都符合规范的 HTML 属性。

查看 “Why Preact instead of Alpine?” 中的讨论以了解更多详情。

原生 JavaScript

请参阅下面的答案。

模板 DSL

还研究了创建 DSL 以编写交互式模板的可能性。用该模板 DSL 编写的代码随后将被编译为 JavaScript 和 PHP。然而,创建生产级的模板编译器是复杂的,将是一项庞大且风险高的精力投资。这种方法仍在未来考虑中,指令作为编译目标。

作为区块开发者,我为什么要使用 Interactivity API 而不是 React?

在前端使用 React 与 PHP 中的服务端渲染并不顺畅。每种使用 React 渲染区块的方法都必须使用客户端 JavaScript 加载内容。如果您仅在客户端渲染区块,通常会导致糟糕的用户体验,因为用户在等待内容加载时会盯着空占位符和旋转加载图标看。

在 PHP 扩展(如 v8js)中使用 JS 也是可能的,但不幸的是,PHP 扩展不具备向后兼容性,只能在有 PHP 回退方案时使用。

现在,可以在 PHP 中服务渲染区块,同时使用 React 在前端渲染相同的区块。然而,这会导致糟糕的开发体验,因为逻辑必须在 PHP 和 React 部分之间重复。不仅如此,您现在还要面对由 WordPress 钩子引起的细微 bug!

想象一下安装一个带有修改服务端渲染 HTML 的钩子(过滤器)的第三方插件。假设此过滤器为您的区块 HTML 添加了一个 CSS 类。该 CSS 类将存在于服务端渲染的标记中。在前端,您的区块将在 React 中再次渲染,但现在内容将不包含该 CSS 类,因为没有办法将 WordPress 钩子应用于 React 渲染的内容!

另一方面,Interactivity API 旨在与 WordPress 钩子完美配合,因为指令通过行为增强了服务端渲染的 HTML。这也意味着它与 WordPress 后端 API(如 i18n)开箱即用。

总之,使用 Interactivity API 而不是仅使用 React 具有以下好处:

  • 如果您使用 React,您的交互式区块必须在客户端生成与服务端 PHP 中相同的标记。使用 Interactivity API,则没有这样的要求,因为指令被添加到服务端渲染的 HTML 中。
  • Interactivity API 对 PHP 更友好。它与 WordPress 钩子或其他服务端功能(如国际化)开箱即用。例如,使用 React,您无法知道服务器上应用了哪些钩子,它们修改后的内容会在水合后被覆盖。
  • 所有 使用标准 的好处。

与仅使用 jQuery 或原生 JavaScript 相比,Interactivity API 有哪些好处?

主要区别在于 Interactivity API 是声明式和响应式的,因此编写和维护复杂的交互体验应该变得容易得多。此外,它专为与区块配合工作而设计,提供了一个标准,带来了上述好处,如区块间通信、兼容性或站点级功能,例如 客户端导航。

最后,与 jQuery 相比,Interactivity API 运行时约为 10 KB,要轻量得多。实际上,目前正努力在整个 WordPress 生态系统中移除像 jQuery 这样的大型框架,这将有助于在这方面取得进展。

我需要了解 React、PHP 和这个 Interactivity API 吗?

如果您想使用此 API 为区块添加前端交互性,简短的回答是肯定的。如果您的区块不具有交互性,区块创建工作流将保持完全相同。

Interactivity API 引入了一种新的标准方法,以促进将交互行为集成到 WordPress 的前端部分。这意味着您仍然需要使用 React 来处理区块的编辑器部分。

另一方面,如果您想创建一个交互式区块,使用 Interactivity API 您不必处理复杂的主题,如工具、与 WordPress 的集成、区块间通信或交互部分的服务端渲染。

Interactivity API 能否在区块之外使用?

当然可以,它不限于区块。您会看到很多关于 Interactivity API 如何提供创建交互式区块的标准提及,但这只是因为那是最常见的用例。更笼统地说,Interactivity API 标准可用于为 WordPress 的任何部分的前端添加“交互行为”。

有关在区块之外使用任意 HTML 使用 Interactivity API 的详细信息,请参见 wp_interactivity_process_directives 函数。

这意味着我必须将所有交互式区块迁移到此 API 吗?

不。不在 Interactivity API 范围内的区块可以与使用它的区块共存。但是,如上所述,请记住,对于使用该 API 的区块有一些好处:

  • 区块之间可以轻松地相互通信。有了这个标准,默认情况下就会处理这种通信。当不同的区块使用不同的前端交互方法时,区块间的通信会变得复杂,而如果由不同的开发者创建区块,这种通信几乎不可能实现。
  • 组合性与兼容性:你可以组合交互式区块,将它们嵌套在具有定义行为的结构中,并且由于遵循相同的标准,它们完全跨兼容。如果每个区块都使用不同的交互方法,它们可能会互相破坏。
  • 发送到浏览器的数据量会更少。如果每个插件作者都使用不同的 JS 框架,前端将加载更多代码。如果所有区块都使用同一个框架,代码就可以复用。
  • 如果页面上的所有区块都使用此标准,则可以启用站点范围的特性,例如客户端导航。

使用此 API 对性能有何影响?对于非常简单的用例,值得加载 Interactivity API 吗?

该 API 在设计时已考虑到性能,因此不应成为问题:

  • 指令所需的运行时代码仅为 ~10 KB,并且只需为所有区块加载一次。
  • 属于 Interactivity API 的所有脚本模块(包括 view.js 文件)都将加载而不会阻塞页面渲染。
  • 有关在区块进入视口后延迟加载脚本的可能性背景信息,请参阅 讨论 #52723。这样可以在不影响用户体验的情况下优化初始加载。

它与 Core Translation API 配合工作吗?

由于 Interactivity API 与服务器端渲染完美配合,你可以使用所有 WordPress API,包括 __() 和 _e()。你可以用它来翻译 HTML 中的文本(就像通常所做的那样),甚至可以在 在服务器端使用 wp_interactivity_state() 时在 store 中使用它。它可能看起来像这样:

// render.php
wp_interactivity_state( 'favoriteMovies', array(
      "1" => array(
        "id" => "123-abc",
        "movieName" => __("someMovieName", "textdomain")
      ),
) );

Interactivity API 需要一个与脚本模块兼容的翻译 API。有关此项工作的背景信息,请参阅 #60234。

我担心 XSS;JavaScript 能注入到指令中吗?

不能。Interactivity API 仅允许将 References 作为值传递给指令。这样就不需要 eval() 完整的 JavaScript 表达式,因此无法执行 XSS 攻击。

它与自定义安全策略配合工作吗?

是的。Interactivity API 不使用 eval() 或 Function() 构造函数,因此不违反 unsafe-eval 内容安全策略。它还旨在与任何 自定义内容安全策略 配合工作。

你可以使用指令发起 AJAX/REST-API 请求吗?

当然可以。由指令调用的动作和回调可以执行 JavaScript 函数能做的任何事情,包括发起 API 请求。