Htmx温和批评


在工作中,我们非常喜欢 Htmx 的基本简单理念。基于在团队中使用 Htmx 进行非平凡用户界面,我们发现以下情况实际上并不简单,而且相当复杂。

继承 Htmx 属性绝对是一个错误
在代码片段中,它非常令人惊讶,而且是隐式的。就像在 CSS 中一样,继承是一种廉价的 hack,但你付出了多少就会得到多少。
它与作者关于行为局部性的合理论点相矛盾。它不是局部的,它来自那里或其他模块。几乎是动态绑定。

默认继承因各种属性而异(例如, hx-delete不是继承的,但 hx-confirm和hx-ext是)。因此,您必须记住这些例外情况,最终您会对所有事情都一清二楚,这意味着继承毫无意义。

大多数有趣的 Web 应用都无法完全取代 DOM 元素
因为 DOM 元素几乎总是具有浏览器本地状态,例如

元素的打开/关闭状态、元素的输入、下拉元素的打开/关闭状态(请注意,单击时不会由元素的属性编码)。如果直接用 Htmx 的简单快乐路径替换 outerHTML,则所有这些状态都会丢失。

即使morphdom也会覆盖一些你认为不会覆盖的内容,所以我们必须修补它以避免干扰输入元素和详细信息元素。

将状态存储在 DOM 元素本身中不是一个好主意
Morphdom 旨在解决上一个标题带来的问题,但我们发现 Htmx 的工作方式假设它基于批量替换元素:它将元素的请求队列存储在 DOM 元素本身上。当您从此元素或指向它的另一个元素发起请求时,您有一个请求队列。通过批量替换 DOM 元素可以避免一些严重的故障模式,因为队列被重置。但是使用 morphdom,由于元素被保留,因此队列被保留。您现在处于一种未定义的行为状态,其中违反了 Htmx 的设计。

默认排队模式很疯狂
默认情况下,如果您在同一队列(元素)上触发另一个请求,Htmx 将取消正在进行的请求。这是默认策略。我们后来发现了这一点。这非常不直观,这意味着我们正在失去工作。

事件触发器是非本地的
事件触发器通常有助于使事情发生,但它们是一种非局部效应,并且存在与属性继承类似的问题。服务器端语言中的一些 DSL 工作可以帮助解决这个问题,但在某种程度上感觉像老式的基于 JavaScript 回调的编程;你“订阅”正在发生的事件并执行某些操作。

组件状态无法很好地维护
一个更广泛的问题,类似于 DOM 元素状态问题,是您自己的组件有自己的状态。例如,如果您想要一个由三个部分组成的页面,这些部分有服务器需要的自己的状态(例如一组结果中的哪一页)以及某些组件(例如 React 或 WebComponents)需要的状态,那么您就会遇到父组件和子组件之间状态同步的问题。

Htmx 对此没有提供很好的解决方案。我们有一些想法,但它们都有很大的问题:使用查询参数、使用隐藏的表单输入、使用事件触发器。
React 和 Halogen(另请参阅Halogen 在各方面都比 React 强)确实对此有答案。在这两种情况下,子组件都有自己的状态,父组件可以向它们提供“props”,这些“props”几乎就是“建议”,它们也有自己的内部状态,并且可以选择忽略/优先于 props。props 通常来自服务器或从服务器派生,状态通常是某种客户端状态。

我们经常需要使用 React 来处理现成的组件或必须使用的组件,而这些组件只是 React 提供的。React 和 Htmx 无法很好地交互。

  • 我们利用 WebComponents 做了一些不尽人意的工作,但这些东西都有着令人惊讶的奇怪限制。
  • 我们还直接与我们在服务器端语言中使用的 React 组件建立了桥梁,但总的来说,Htmx 和 React 会争夺对状态流和 DOM 元素管理的控制权。
  • 我们玩过 Alpine,它很不错,但它代表了另一个客户端编程库,因此如果你的代码库中已经有 React,那么它就是多余的。

积极的一面
我们目前的想法是,能够使用服务器端语言是一个巨大的明显且无争议的胜利,团队中没有人愿意再用 TypeScript 编写所有这些业务逻辑:

  • 我们的数据库类型到前端类型不需要序列化。
    • 没有数据泄漏,也不需要 GraphQL。
  • 我们可以使用(我们认为)更强大的服务器端语言抽象功能。
  • 我们可以在服务器端语言中使用表单生成器;而不必在一个前端和一个后端分别实现相同的验证。
但上述缺点是真实存在的。

React 中的 Htmx?
一个有吸引力的未来方向可能是在 React 中重新实现 Htmx:

  • 服务器发送一个 JSON blob,React 将其转换为虚拟 DOM 组件。
  • 这将解决组件状态问题。
  • 这意味着我们不需要特殊的桥梁来使用 React 组件。
  • 它会让我们使用与 React 连接的 Web 获取库,并小心地避免 Htmx 做出的排队选择。
  • 它还可以解决形态问题和浏览器 DOM 输入元素问题,这在 React 中已经基本解决了。
这样,我们就可以放弃对 Htmx 的依赖,但保留这个想法的好处。也就是说,给定预算来着手进行如此大的工作。