两者都拥抱了网页的HTML+CSS基础,并增强其功能,以便在几乎不需要JavaScript的情况下实现流畅的用户界面。
虽然这两个项目共享许多基本价值观甚至目标,但它们在实现这些目标的方式上有所不同。到本文结束时,您将对它们的相似性和差异有一个良好的高层次理解。
我主要的经验是与 Hotwire 相关。我对它进行了广泛的研究。我对 HTMX 的兴趣主要是为了扩展我的思维视野:通过学习其他技术,我常常能找到有价值的新想法。
为了确保观点的平衡 我购买并阅读了书籍 Hypermedia Systems,由 HTMX 的作者撰写。他们解释了他们的想法,并逐步构建一个基于 HTMX 的应用程序。
如果你注意到我误解了什么,请在评论中或直接告诉我,我会改进这篇文章。
两个框架都认可以 HTML 为中心的方法的价值。这与许多单页面应用(SPA)JavaScript 框架在浏览器中实现的 厚客户端模式 相对立。它们将 HTML 视为不超过一种渲染媒介。
另一方面,像 Hotwire 和 HTMX 这样的框架认识到,当 HTML 被视为 应用状态的引擎 时,它更加强大。将 HTML 设计为 瘦客户端 技术的原则虽然古老,但仍然有效。HTML 经过了许多进步,现代浏览器中的 HTML5 + CSS 组合非常强大。然而,这还不足以构建丰富的现代交互式应用程序。几乎达到了,但还差一点。
像 Hotwire 和 HTMX 这样的框架旨在缩小差距,使服务器端渲染的 HTML 能够提供现代用户体验。它们是用 JavaScript 实现的,但设计上尽量减少自定义应用 JavaScript 的需求。事实证明,这使得大多数现代 web 应用程序的构建变得更加容易。
本文不是这两个框架的教程。我将尽量给你提供对这两个框架的最简短介绍,足以让你理解本文的其余部分,如果你对这两个框架中的任何一个或两个都不熟悉的话。
如果你对 Hotwire 甚至有一点基本的了解,我建议你跳到下一章。
'Hotwire 代表 “HTML 通过网络”。它是多个库的总称。主要的库是 Turbo.'
Turbo 通过引入几个关键概念来增强 HTML:
- Turbo Drive 拦截常规浏览器导航,而是执行 AJAX 请求并自行处理响应。它通过避免完全重新加载页面来加快导航速度。它还添加了缺失的 HTML 功能,例如使链接执行非 GET 请求的能力。
- Turbo Frames 将页面分解为独立的上下文。它们实现了页面内页面的心理模型。这提供了一种自然的方式来构建集成的用户界面,这些用户界面生活在同一页面上,但实现起来就像是一组独立的页面。例如:内联编辑可以被视为在单个页面中的多页面编辑流程,位于一个框架内。
- Turbo Streams 允许服务器渲染小的目标指令,以修改页面的特定部分。它们可以作为表单提交的响应或通过 WebSocket 发送,以启用协作应用程序。
所有 Turbo 功能的基础是这样的理念:开发应该尽可能地像构建一个普通的服务器端渲染 HTML 应用程序,只不过这个应用程序的表现要好得多。所有的业务逻辑都在服务器上,界面通过向客户端传递 HTML 来控制。
在这还不够的情况下,Hotwire 的第二个库就派上用场了:Stimulus。你可以把 Stimulus 看作是 jQuery 的现代替代品:
- 使得对事件的反应和修改 DOM 变得简单。
- 不会接管 HTML,而是将 HTML 视为应用状态的来源。
- 最适合用于添加 HTML 默认缺乏的特定功能。
它通过附加小的 Stimulus 控制器 来实现这一点,这些控制器附加到特定的 DOM 元素上,并允许你使用 JavaScript 来增强该元素的一些自定义行为。例如,在使用 popup
控制器的元素上添加 data-action="mouseenter->popup#show"
将导致当我们将鼠标悬停在其上时,控制器上的 show
JavaScript 方法被执行。
如果你对 HTMX 甚至有一点基本的了解,我建议你跳到下一章。
HTMX代表**“超文本标记扩展”**。它旨在通过允许来增强HTML:
- 任何元素发出 HTTP 请求。
- 任何事件触发 HTTP 请求。
- 请求中使用的任何 HTTP 动词。
- 页面中需要更新的任何部分与 HTTP 响应.
它通过一组可以放置在任何元素上的属性来实现这一点,这些属性通过 HTMX 实现了额外的功能。这样的属性有很多,以下是一些示例,让你了解一下:
hx-post="url"
将 HTTP 请求从常规 GET 转为 POST。所有 HTTP 动词都有等效属性。hx-swap="outerHTML"
将使 HTMX 使用 HTTP 响应替换整个目标元素,而不仅仅是其内容。hx-trigger="mouseenter"
将在我们将鼠标移动到元素上时触发 HTTP 请求,而不是等待点击。hx-target="#container"
将使用 HTTP 响应更新 id 为container
的元素,而不是我们点击的元素。
还有许多其他属性。其中一些支持迷你 DSL,以进一步自定义行为。所有属性都是正交和互补的。总体思路是将这些支持 HTMX 的属性组合在一起,以构建复杂的界面。
例如,这里有一个列表元素,当按住 ctrl 键点击时,将向 \generate
端点发出一个 POST 请求,并将响应添加为列表中的最后一项:
`1 2 3
从根本上讲,两者都基于相同的前提:
- HTML 和 CSS 提供了丰富的交互体验界面。
- 单页面应用程序的构建方法使用 HTML 仅用于渲染,增加了附带的复杂性。
- 通过将 HTML 视为应用程序状态的源并在服务器上渲染,可以避免额外的复杂性。
综合来看,他们得出结论,有很大的机会通过不同的方法彻底简化 web 应用程序开发。
而两者都采取了相同的高层次方法:
- 将业务逻辑保留在服务器上。
- 使 HTML 成为应用程序状态的存储。
- 增强 HTML 以实现现代用户体验。
- 仅在增强的 HTML 不足时使用 Javascript 进行自定义行为。
从远处观察,这两种解决方案看起来非常相似,仿佛它们几乎是同一件事。
仔细观察,他们采用了不同的原则,这导致了他们在感受上的显著差异。剧透警告:我认为两者都很棒,原因各不相同。
他们的设计选择在以下方面不同:
- 隐式增强与显式增强的比例。
- 在何种程度上推动边界,之后你需要编写自定义的Javascript。
- 它在多大程度上依赖后端以充分利用其功能。
一个增强 HTML 的框架需要做出选择:何时应该由应用代码显式激活增强,何时应该根据上下文隐式激活。换句话说:我们希望这个框架感觉有多“神奇”?
Hotwire,特别是Turbo,很多时候都倾向于“魔幻”:
- 默认情况下,一旦你在页面上导入 Turbo,它就会激活 Turbo Drive 并接管导航。你可以关闭它,但默认情况下它会启用一组增强功能,而无需你做任何事情。
- Turbo Frames 努力使“页面中的页面”的思维模型正常工作。在最常见的情况下,如果你将框架放在正确的位置,所有常见路径都会正常工作。框架默认启用许多增强功能。你应该主要使用自定义属性来打破默认行为。
这是故意的。如果你熟悉 Ruby on Rails,你会注意到 Hotwire 继承了 Rails 的这种方法。
HTMX 采取了完全不同的方法。它明确选择成为一个 低级增强 库,只做明确的事情。当 HTMX 被包含在页面上时,默认情况下它做:什么都不做。每一项功能都是通过明确地将一个 hx-
属性添加到元素上来启用的。没有属性,就没有增强。
唯一的例外是 hx-boost
,当它放置在一个元素上时,会增强该元素中包含的链接和表单。将 hx-boost
放在 BODY 标签上可以获得 Turbo Drive 开箱即用的一些功能。然而,HTMX 强调这是对库哲学中 仅有显式增强 的务实例外。
这两种方法各有利弊:
- Turbo 将在大多数功能上减少您的工作量,但当“魔法”停止工作时会更麻烦。
- HTMX 将需要您更多的工作,但会让您完全控制特定元素上哪些部分是活动的。
如果你有兴趣在不编写自定义 JavaScript 的情况下尽可能多地实现功能,HTMX 将帮助你走得更远。由于它被设计为一个低级工具包,它有大量的属性可以以多种方式组合,从而实现许多不同的行为。你可能需要一段时间来学习所有的属性及其选项,但这将使你走得很远。它的 DSL 甚至可以通过直接在 hx-
属性中定义的 CSS 过渡来实现动画等功能。
另一方面,Turbo 在后台非常努力地工作,以便为其增强功能提供一个连贯的心理模型,这将使你在不必记住太多选项的情况下走得很远。Turbo 的增强功能都专注于与服务器的交互。一旦你需要一些额外的 UI 行为,它就会引导你使用 Stimulus,期望你在其中编写一小段自定义的 JavaScript。
再次,两种方法各有其优缺点:
- HTMX 有更大的 API 面积需要记忆,但默认提供更多功能。
- Turbo 和 Stimulus API 使记住它们提供的所有功能变得更容易,但你会更频繁地使用自定义 Javascript。
两者都没有错,这在很大程度上取决于什么对你和你的团队来说感觉更自然。
Hotwire 源于一个主要的后端框架:Ruby on Rails。HTMX 则不是。这一点很明显。Hotwire 仍然与后端无关,然而,如果你使用 Rails,它提供了与许多事情的优秀集成。而且,它建议其他框架使用 Rails 集成作为 参考后端集成。HTMX 对后端的关注则少得多。
这表明当一个功能集确实需要特定的后端部分才能发挥作用时。例如,Hotwire 的协作功能,只需工作 与 Rails。通过 WebSockets 与后端的集成是 Turbo 的一流功能。而 Stimulus 被微调以很好地处理从后端流式传输的更改。一旦你有了正确的后端集成,使 Hotwire 的协作功能正常工作是非常简单的。HTMX 确实支持 WebSockets 集成,但 它是一个扩展,在书中甚至没有提到。
Hotwire 和 HTMX 都可以与任何后端技术栈一起使用,这正是 HTML-over-the-wire/超媒体方法的核心。然而,根据你选择的后端技术栈和应用程序的需求,你可能会发现其中一个更容易集成。
不出所料,对于 Ruby on Rails,turbo-rails gem 的开发要远远超过 htmx-rails gem。
很有趣的是,如何从相同的一组基本价值观出发,得出两个不同的高质量解决方案,这两个方案都尊重基本原则,但使用起来却感觉非常不同。
作为一名长期的 Rails 开发者,我选择的库是 Hotwire。我喜欢它按预期工作,但有时我希望在需要做不同的事情时它能更明确一些。阅读关于许多 hx-
属性的选项让我思考如何构建我的刺激控制器,以便摄取微型 DSL,从而允许直接从 HTML 中获得更多控制。
那么总体上哪个更好呢?就像编程中的许多问题一样,答案令人沮丧:这要看情况。
你呢,你更喜欢哪种方法 用于你当前的团队和项目?
如果您喜欢这个比较并希望了解更多关于 Hotwire 的信息,请考虑在下面订阅。我正在制作一本针对 经验丰富的 Rails 开发者 的 Hotwire 电子书,以显著加快您成为 经验丰富的 Hotwire 开发者 的旅程。我将通过我的订阅者名单宣布 beta 版的推出,并提供特别折扣。