- 前端
【免费下载链接】htmx
htmx - high power tools for HTML
导读:本文以 htmx 官方博客《Alternatives to htmx》为基础,系统梳理超媒体驱动应用(HDA)路线下除 htmx 之外的十余个代表性库与框架——从成熟的 Unpoly、Hotwire Turbo,到极简的 htmz、Nomini、fixi.js,再到 SSE 取向的 Datastar 与 Alpine 生态的 Alpine-ajax。读完本文,你将理解这些方案的定位差异、核心机制、体积与适用场景,并能在 htmx 之外为你的服务端渲染应用找到合适的超媒体搭档。
htmx 官方多次强调一个核心观点:超媒体(hypermedia)的思想比 htmx 这个具体实现更重要。在 hypermedia-driven-applications.md 一文中,作者 Carson Gross 将 HDA 架构定义为 MPA(多页应用)与 SPA(单页应用)的"合题":用声明式、内嵌在 HTML 中的语法取代命令式脚本,并让服务器以 HTML 超媒体而非 JSON 数据的形式与应用交互——即坚持 HATEOAS(超媒体作为应用状态引擎) 的 REST 架构约束。
围绕这一思想,生态中涌现了大量与 htmx 殊途同归的实现。本文逐一介绍这些值得纳入选型视野的方案,并结合本仓库中的源码与文章,说明它们与 htmx 的异同、各自的定位,以及什么时候应该"放下 htmx"。
一、先看 htmx 自己的定位与能力边界
在展开替代方案之前,有必要先明确 htmx 本身"完成"了什么。根据仓库 README.md 的说明,htmx 允许你在 HTML 中直接使用 AJAX、CSS 过渡、WebSocket 与 Server-Sent Events,通过hx-*属性构建现代用户界面;它体积小(约 14k min.gz'd)、无依赖、可扩展,是 intercooler.js 的后继者。
README 中提出的四个"为什么"构成了 htmx 的动机:
- 为什么只有
<a>和<form>能发起 HTTP 请求? - 为什么只有
click与submit事件能触发它们? - 为什么只有 GET 与 POST 可用?
- 为什么只能替换整个屏幕?
通过移除这些"任意限制",htmx 补全了 HTML 作为超文本的缺失能力。这些能力直接体现在 src/htmx.js 的实现中,例如hx-get、hx-post、hx-target、hx-swap等属性(本仓库源码中即有多处对应实现)。与之呼应的是,htmx 的声明式写法还体现了 Locality of Behaviour(行为局部性,LoB) 原则:<button hx-get="/clicked">Click Me</button>的行为一眼可见,不像 jQuery 那样需要跨文件才能拼出完整行为。
理解了这条能力边界,就更容易理解下面这些替代方案各自"补全"了哪一块。
二、Unpoly:Ruby 社区十年打磨的渐进增强框架
Unpoly 是一个成熟的前端框架,尤其在 Ruby 社区被重度使用了超过十年。它提供同类最佳(best-in-class)的渐进增强(Progressive Enhancement)能力,并拥有许多实用概念,例如layers(层级)与精细的表单校验(form validation)。
Unpoly 的作者 Henning Koch 曾接受 Carson Gross 的专访,访谈全文收录在 interviews/henning_koch.md 中。访谈中有几个值得留意的细节,恰好解释了 Unpoly 的设计取向:
- 它源于 makandra(一家 Rails 咨询公司)在大量客户项目中的模式提炼,本质上是"HTML6 幻想规范"的落地:如果 HTML6 专为服务端渲染应用而设计,它会包含哪些特性?
- 与 Rails 一样,Unpoly 崇尚"为一切提供强默认值",偏好不显眼的约定优于显式配置——你甚至可以在完全不改动 HTML 的前提下让 Unpoly 接管所有链接和表单。
- Koch 认为,对大多数中等规模应用而言,超媒体路线往往比 SPA 模型交付更好的结果;浏览器原生处理焦点管理、并发输入、网络不稳定等大量边界情况,而用 JavaScript 模拟页面过渡很难达到同等正确性。
如果你看重渐进增强、成熟度和 Rails 生态,Unpoly 是与 htmx 气质最接近的"重武器"之一。
三、Triptych:把超媒体控制权写进 HTML 规范的提案
Triptych 是一组三份提案,目标是让更通用的超媒体控制能力直接进入 HTML 规范:
- 允许在 HTML 中直接使用更多HTTP 方法(不止 GET/POST);
- 允许按钮作为独立的超媒体控件(而不只是表单的一部分);
- 允许超媒体控件将页面上任意元素作为替换目标。
该项目正在被引入 WHATWG,以争取进入 HTML 规范;同时它附带了一个polyfill,今天就可以用来按提案实现应用。
不难发现,Triptych 的三点主张与 htmx 在 README.md 中提出的四个"为什么"高度重合——它们本质上是把 htmx 已经在实践中赋予 HTML 的能力,尝试以标准化的方式"追认"进规范。从"通用化超媒体控件(generalized hypermedia controls)"这一研究脉络看,htmx 团队自己的极简实现 fixi.js 正是这一思想的另一条路线。
四、fixi.js:htmx 团队自己的极简实现
fixi.js 是htmx 团队对"通用化超媒体控件"的极简实现,重点放在"尽可能小"上,刻意省略了 htmx 中的许多功能。
它的目标数据(按原文档所述):约 3.5k(未压缩、未 minify),压缩后约 1.3k,同时保持可读、可调试,因此可以直接包含进项目而无需任何构建转换。
fixi.js 的价值在于:它证明了"超媒体控件的核心"可以收敛到极小体积,把 htmx 中那些"锦上添花"的功能(如扩展、历史管理、指标等)全部剥掉之后,剩下的本质仍然成立。如果你只需要最基础的 AJAX 式交互、且极度在意包体积,fixi.js 是一个值得关注的极简选项。
五、Datastar:从"htmx 的 TypeScript 重写"独立出来的 SSE 取向方案
Datastar 最初是作为 htmx 的TypeScript 重写 + 现代工具链提案而诞生的,后来发展成独立项目,并采取了一种SSE(Server-Sent Events)取向的超媒体路线。
它的特色在于:把 htmx 与 Alpine.js 的功能合并进一个干净的小包,而且体积比 htmx 更小。换句话说,如果你既想要超媒体驱动的服务端交互,又想要 Alpine 风格的响应式前端能力,Datastar 尝试用单一依赖同时满足两者,并借助 SSE 实现服务器到浏览器的推送式更新。
六、Nomini:最小的"响应式变量 + 局部页面替换"实现
Nomini 是一个拥抱"以 JavaScript 作为简单增强手段"这一原始理念的超媒体实现:它只希望在静态为主的页面之上,添加一层极薄的 LoB(行为局部性)层,从而以最小的客户端代码实现强大的服务端驱动 Web 应用。
按原文档所述,它目前是同时提供**响应式变量(reactive variables)与局部页面替换(partial page swaps)**的库中体积最小者:约 2.8k(minified),约 1.4k(minzipped)。
本质上看,Nomini 可以理解为 Datastar 的微型重实现,或"Fixi + Alpine.js"的组合体——它是面向响应式服务端驱动 UI 的极简、务实积木。这一描述与 htmx-sucks.md 中对"极微库"的调侃形成了有趣对照:Nomini 恰恰选择在"最小化"与"正确性"之间做出自己的权衡。
七、µJS:自带预取、SSE 与 morphing 的无依赖小库
µJS 是一个约5k、无依赖的小型库,实现了大量超媒体思想,特性包括:
- 预取(pre-fetching)
- SSE(Server-Sent Events)
- 基于 idiomorph 的 DOM morphing(morphing 即把新旧 DOM 做最小差异合并,而不是整体替换)
其中 idiomorph 正是 htmx 生态中用于平滑 DOM 过渡的 morphing 方案,µJS 直接将其纳入核心,说明它在"如何优雅地应用服务端返回的 HTML"上与 htmx 共享同一套技术路线。
八、Alpine-ajax:把 htmx 式概念内嵌进 Alpine 生态
如果你已经是 Alpine.js 的用户(Alpine 也是常与 htmx 搭配使用的脚本库),那么值得关注Alpine AJAX:它是一个 Alpine 插件,把类似 htmx 的概念直接集成进 Alpine。
它的定位非常清晰:不引入第二套心智模型,而是让 Alpine 的表达式体系直接获得 AJAX/超媒体交互能力。对于已经在用 Alpine 管理前端状态、只想补上"服务端 HTML 片段交换"这一块的项目,Alpine-ajax 是侵入性最小的选择。
九、Hotwire Turbo:37Signals 出品的成熟前端框架
Turbo 是Hotwire技术套件的组成部分,出自以 Ruby on Rails 闻名于世的37Signals。它是一个打磨精良的前端框架,在 Rails 社区被广泛使用,但同样可以搭配其他后端技术。
值得注意的一点:原文档提到,一些与 htmx 相处不愉快的人转而喜欢上了 Turbo。这暗示两者的体验差异可能集中在约定(convention)与配置(configuration)的取向上——Turbo 更强调开箱即用的框架化约定,而 htmx 更强调"你说了算"的属性化声明。结合 hypermedia-driven-applications.md 的"HDA 风格库"清单(其中同时列出 htmx、Unpoly、TwinSpark、Hotwire),可以看到 Turbo 在作者眼中与 htmx 属于同一超媒体谱系。
十、htmz:用 iframe + location.hash 实现"广义转嵌"的天才小库
htmz 是一个令人拍案叫绝的极简库,它利用了 HTML 的一个既有事实:锚点与表单本来就有target属性,可以指向一个iframe。将这一点与location.hash组合起来,就能实现"广义转嵌(generalized transclusion)"——即把另一个文档的片段动态嵌入当前文档。
原文档强调,这就是该库的全部源码(作者声明"我不是在开玩笑"):
<iframe hidden name=htmz onload="setTimeout(()=>document.querySelector(contentWindow.location.hash||null)?.replaceWith(...contentDocument.body.childNodes))"></iframe>这行代码的机制可以拆解为:
- 隐藏的
<iframe name="htmz">作为所有链接/表单的target,让响应在 iframe 内加载而不跳转页面; - iframe 的
onload触发后,读取 iframe 的location.hash(即服务端返回内容中约定的目标选择器); - 用
document.querySelector(hash)找到页面上的目标元素,再以replaceWith(...contentDocument.body.childNodes)将 iframe 文档体替换进去。
把"页面局部更新"压缩到一行 HTML,这正是超媒体思想"以最小的代价复用浏览器原生能力"的极致示范。它也与 htmx 在 src/htmx.js 中通过属性系统完成的"局部替换"目标一致,只是选择了完全不同的实现杠杆。
十一、TwinSpark:带 morphing 能力、已在生产环境验证的同类库
TwinSpark 由 Alexander Solovyov 创建,与 htmx 类似,特性包括morphing(DOM 变形合并)等。原文档指出,它正在被日活 10 万以上的站点在生产环境使用。
对于担心"超媒体库只适合玩具项目"的开发者,TwinSpark 提供了一个生产级佐证;同时它也被 hypermedia-driven-applications.md 的 HDA 风格库清单明确收录,说明在作者看来它与 htmx、Unpoly、Turbo 处于同一技术阵营。
十二、jQuery:一切的开端——load()与 intercooler.js 的血脉
最后是"元老"jQuery。它的load()方法可以把一个 URL 加载进指定元素:
$("#result").load("ajax/test.html");这个方法正是intercooler.js(htmx 的前身)的灵感来源之一。如果你已经在使用 jQuery,load()也许就够用了。
这一点在仓库的另一篇文章 htmx-sucks.md 中甚至被拿来作为批评 htmx 的论据——作者(刻意扮演批评者)展示了 2008 年的 jQuery 写法:
$( "#result" ).load( "ajax/test.html" );与 htmx 的写法:
<button hx-get="/ajax/test.html" hx-target="#result"> Load </button>两相对照,恰好呈现了超媒体演进的两端:jQuery 用命令式脚本表达"加载到元素",htmx 用声明式属性表达同一件事。而从 locality-of-behaviour.md 的视角看,后者把行为"收拢"到了元素本身,这正是两者在软件设计层面的根本分野。
十三、横向对比:一张表看懂各方案定位
| 方案 | 体积/规模(原文档所述) | 核心机制与取向 | 生态/背景 | 最适合的场景 |
|---|---|---|---|---|
| htmx | 约 14k min.gz'd,无依赖 | 声明式hx-*属性,AJAX/WS/SSE | 本仓库,intercooler.js 后继 | 想用 HTML 属性直接获得 AJAX 能力 |
| Unpoly | 成熟大型框架 | 渐进增强、layers、表单校验 | Ruby/Rails 社区,十年以上 | 看重渐进增强与成熟约定 |
| Triptych | 规范提案 + polyfill | 把通用超媒体控制写进 HTML 规范 | WHATWG 提案 | 关注 HTML 标准演进 |
| fixi.js | 约 3.5k 未压缩 / 约 1.3k 压缩 | 极简通用超媒体控件 | htmx 团队 | 极致追求小体积 |
| Datastar | 比 htmx 更小 | SSE 取向,htmx + Alpine 合一 | 源自 htmx TS 重写提案 | 想要 SSE 推送 + 响应式前端 |
| Nomini | 约 2.8k minified / 约 1.4k minzipped | 响应式变量 + 局部页面替换,LoB 薄层 | 新兴项目 | 最小化的响应式服务端 UI |
| µJS | 约 5k,无依赖 | 预取、SSE、idiomorph morphing | 新兴项目 | 需要预取与 DOM morphing |
| Alpine-ajax | Alpine 插件 | 把 htmx 式概念集成进 Alpine | Alpine 生态 | 已是 Alpine 用户 |
| Hotwire Turbo | 成熟框架 | 约定优先的页面替换 | 37Signals / Rails | 想要开箱即用的框架化体验 |
| htmz | 单行 HTML | iframe + location.hash 转嵌 | 新兴项目 | 极简页面局部更新 |
| TwinSpark | 同类成熟库 | morphing,生产验证 | 独立作者 | 需要 morphing 与生产背书 |
| jQuery | 经典库 | load()方法 | 全行业历史 | 已在用 jQuery |
十四、结论与选型建议
原文档的结论值得反复咀嚼:如果 htmx 不适合你的应用,上面这些库中的某一个,可能恰好能让你继续享受超媒体模型的收益。超媒体世界正在发生大量令人兴奋的事情,而每个库都以自己的方式贡献其中。
结合仓库中的整体论述,可以提炼出几条务实的选型建议:
- 先确认路线,再挑工具:HDA 路线的共同前提是"服务器返回 HTML 超媒体、客户端以声明式方式消费它"(见 hypermedia-driven-applications.md)。在这个前提下,htmx、Unpoly、Turbo、TwinSpark 属于同一条主线,选谁更多取决于生态与约定偏好。
- 体积敏感的项目:fixi.js、Nomini、htmz、µJS 都把"小"当作第一公民,其中 htmz 甚至只有一行源码,适合作为学习材料或极致精简场景的参考。
- 已有 Alpine/jQuery 存量:Alpine-ajax 与 jQuery
load()可以以最小侵入融入现有代码,不必推翻重来。 - 关注标准演进:Triptych 正在把"通用化超媒体控件"推向 HTML 规范(相关学术脉络可参见 essays/_index.md 中收录的《Hypermedia Controls: Feral to Formal》研究条目),其方向性意义对理解整个生态的走向很有帮助。
最后,正如原文档作者所说:如果这些项目(尤其是较新的那些)对你有帮助,不妨为它们点亮 GitHub Star——对开源开发者而言,那是最有效的精神鼓励之一。而作为技术选型者,你的收获则是:超媒体不是某一家库的专利,而是一条持续演进、百花齐放的架构路线。
- 前端
【免费下载链接】htmx
htmx - high power tools for HTML
相关推荐
ESP-IDF Partitions API 完全指南:分区表枚举、读写擦除、MMAP 映射与分区烧录
ESP IDF Partitions API 完全指南:分区表枚举、读写擦除、MMAP 映射与分区烧录 导读 本文以 ESP IDF(Espressif IoT
前端astryx BaseTypeahead 无障碍与属性透传审计修复详解:从 changeset 到源码实现
astryx BaseTypeahead 无障碍与属性透传审计修复详解:从 changeset 到源码实现 导读 本文围绕 astryx 设计系统核心包 @as
前端Vime媒体播放器:现代化Video.js替代方案的完整指南
Vime媒体播放器:现代化Video.js替代方案的完整指南 在当今多媒体内容爆炸的时代,一个强大、灵活且易于使用的媒体播放器对于任何网站都至关重要。Vime媒
音视频UI库/组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考