htmx 4.0 发布
文章摘要
2026 年 8 月 28 日,htmx 团队发布了 htmx 4.0.0,这是八个月工作(外加做了一个游戏)的成果。作者 Carson Gross 讲了缘起:他在做 fixi 的时候熟悉了 fetch() 和 JavaScript 异步编程(htmx 一直因为向后兼容而用 XMLHttpRequest),某个晚上 Christian 找到他聊流式 HTML 的想法,让他意识到把内部实现换成 fetch() 会让很多事情变简单。团队从”fixi + htmx 测试套件”的移植起步,一路重新发现了 htmx 当年那样做的理由,新实现最终越来越接近旧实现。
从用户视角看,htmx 4 和 htmx 2 几乎一样,只有三处大改动:
一,属性继承从”默认隐式”改成”默认显式”,这是最大的升级负担。htmx 2 里许多属性会被子元素自动继承,这个行为来自 intercooler.js 时代、灵感来自 CSS,结果也和 CSS 差不多——强大但有时难以理解。htmx 4 里必须在属性名后面显式加 :inherited 后缀(例如把父元素上的 hx-confirm 写成 hx-confirm:inherited)才会被子元素继承。相应地,hx-disinherit 这类属性不再需要,应当删除。
二,事件命名标准化,统一为 htmx:phase:action[:sub-action] 的形式,比如 htmx:beforeRequest 变成 htmx:before:request,htmx:configRequest 变成 htmx:config:request。大部分错误事件收敛为 htmx:error,HTTP 错误响应触发 htmx:response:error;htmx:xhr:* 系列因为改用 fetch() 而移除;htmx:validation:* 移除,改用浏览器原生表单校验。
三,历史记录不再默认使用 localStorage。htmx 2 用 localStorage 缓存页面快照来恢复,但快照会包含第三方 JS 造成的 DOM 变更,恢复后 DOM 在而逻辑不在,这是大量 issue 的来源。htmx 4 改为在后退时重新拉取页面并 swap 进 body(或 [hx-history-elt] 元素),第三方库因此大多能”直接正常工作”;想要本地缓存的话,官方提供了基于 sessionStorage 的 hx-history-cache 扩展。
两个大的新特性:一是内置 morph swap,Michael 在 idiomorph 算法基础上做了改进并无缝集成;二是 hx-partial 标签,类似 out-of-band swap,但当你想做的不只是”用新版本替换某个元素”时语义清晰得多——每个 hx-partial 带自己的 hx-target 和 hx-swap,一次响应可以精确地更新多个不同位置。
扩展生态是这次的另一个兴奋点:hx-preload(鼠标悬停预加载)、hx-download(基于 fetch 的原生下载)、hx-alpine-compat(抹平与 Alpine.js 的兼容问题)、hx-history-cache,以及三个流式 HTML 扩展 hx-sse、hx-ws、hx-multipart。团队还做了自己的小型前端脚本方案 hx-live,灵感来自 Alpine.js、jQuery 和 hyperscript,支持他们称之为”基于 DOM、对 HATEOAS 友好的响应式”。发行版里新增了 htmax.js,把 htmx 和最流行的扩展打包成一个文件。
升级方面提供了命令行检查工具(npx htmx.org@4.0.0 upgrade-check 扫描模板目录),能报出需要加 :inherited 的属性、被重命名的属性(hx-disable 改名 hx-ignore)、被移除的属性(hx-vars 改用 hx-vals 加 js: 前缀,hx-prompt 改为加载扩展),以及旧事件名和被移除的 API。此外还提供了给 LLM 用的 skill 文件(开发指导、调试、扩展编写、从 htmx 2 迁移)。值得注意的是:4.0 不会在 npm 上标记为 latest,2.x 仍是 latest、4.0 走 next 通道直到 2027 年初,以免强制升级那些用不带版本号 CDN 链接的用户;htmx 2 也会无限期继续支持。
HN 评论精华
为什么跳过 3? 这是投票最高的问题之一。MichaelNolan 给出了答案:htmx 2 发布时团队承诺”永远不会有版本 3”(意即不会有破坏性变更),后来发现确实需要一次破坏性变更,那么信守承诺的唯一办法就是跳过 3。_doctor_love 的版本更妙:”Carson 承诺过永远不做版本 3,但他从没说过不能做版本 4。” SoKamil 顺着推理:”指数版本号,下一个大版本是 8。” gwking 说”我已经为 v8 激动了”,作者 recursivedoubts 回了句”这位懂了”。yawaramin 补充了一处纠正:不是”意识到需要破坏性变更”,而是他们被 Fetch API 能解锁的改进给兴奋到了、主动想做破坏性变更;升级完全自愿,没有已知安全问题会逼任何人升级。
LLM 会不会让 htmx 变得没必要,是最实质的一场讨论。 replwoacause 提出:他一直是 htmx 的支持者,但既然 LLM 能替我们写 JavaScript,htmx 那层抽象带来的简化就没那么值钱了,他现在不用 htmx 也过得挺好。作者 recursivedoubts 的回应相当坦然:”我预计 LLM 会伤害 htmx 和大多数小型 web 库的采用。没关系,它一直是一份出于热爱的劳动,用的是 BSD 0 协议。”
反方的观察很有意思。giraffe_lady 说,至少未来几年里,某些偏好和共识被”意外地固化”进了模型里,对 htmx 是好事——Claude 会主动建议小项目用 htmx 而不是更通用的 JS 框架,某个 GPT 模型甚至对他说过一句他专门记下来的话:”htmx 赢下了它一直在做的那场论证。”他拿 Rust 做类比:自己是 OCaml 专家,OCaml 更适合他的问题域,但模型里冻结着”Rust 几乎对什么都更好”的那种另类共识。recursivedoubts 半开玩笑地说,这次把属性继承翻成显式默认,”可能会让很多模型犯迷糊,算了,这是对的事”。sroerick 则认为效果可能相反:LLM 里”简单胜过训练数据”,需要消耗的上下文只有五分之一,生成的代码就会更好,哪怕语言很冷门。vb-8448 认为 htmx 解决的是复杂度问题、而 LLM 并不解决它,反而会推高 htmx 加 web components 这类方案的采用。Capricorn2481 提醒不要混淆概念:htmx 本身就是一个 JS 库,它和手写 JS 是两种不同的应用架构,”如果你只是拿 htmx 来躲 JS,那 LLM 为什么会打消你这个念头?与其 vibe code 一门你都不够懂的语言,不如 vibe code 一个你读起来更轻松的东西——炸了怎么办?” gregwebs 从测试角度批评:htmx 对 DOM 标记的强调不利于简化测试,他在文档里也没看到独立的测试章节,交给 LLM 做的时候状态同步问题不少。
技术栈昵称大赛。 nzoschke 说他现在每个实验都从 Go + htmx + SQLite 起步,并称之为 HUGS 栈;michaelchisari 叫它 GOSH(Go SQLite Htmx),FartinMowler 加上 Alpine 变成 HAGS,35mm 提出 RASX(Rust Axum SQLite Htmx),mlhpdx 贡献了 DASH(DynamoDB、API Gateway、Step Functions、HTMX),pepperoni_pizza 转述了 Reddit 上给 PHP 用户的建议——HAYW 栈,Hypermedia on Anything You Want。Analemma_ 力荐 Django + Postgres 后端配 htmx + Alpine.js 前端,说 Claude 对这套非常在行、给对指令还能保持简洁模块化,”除非你确定需要 React 那种重量级,否则这应该是新项目的第一选择”。arw0n 强烈反对 Django:他最近收拾了好几个 Django 后端,默认 fail-open、校验薄弱、ORM 平庸、测试框架糟糕,用 Go/Java/Rust 管 agent 就没这些问题。
也有唱反调的。 用户 asdf88990 说跳过版本 3 这件事”可以作为 htmx 整体的总结:一个建立在对问题域一知半解之上的自信方案”,并称作者”没跟上二十年的 web 开发进展,现在才追到 2010 年代初的 jQuery 和 backbone 时代”。yawaramin 逐条反驳:htmx 是 2013 年前后 intercooler.js 的直系后代,核心思想(把服务端来的 HTML swap 进 DOM)十多年来始终不变,恰恰是因为看过这二十年,htmx 才躲开了其中几乎所有东西;同时他还当场指出对方疑似在用两个账号自问自答(asdf88990 和 asdfsa32),并 @ 了 dang。
关于”百年 web 服务”这个目标也吵了一架。 ryanisnan 说他仍然怀疑 htmx 能否成为百年 web 服务的基础,但认为这个目标很值得,”除了静态 HTML 我没有更好的选项”。smt88 认为想 100 年甚至 10 年都是典型的 bikeshedding(琐碎纠结),完美是好的敌人,只要输出的是 web 标准,浏览器引擎自会保证它 10 年不倒。接下来这条线迅速自我指涉地跑题了:ashwinsundar 说”讨论架构能不能撑 100 年是 bikeshedding,这句话本身也是 bikeshedding”,xp84 补刀”讨论 bikeshedding 是不是 bikeshedding,才是 bikeshedding 的巅峰”,最后 ashwinsundar 只回了一个词”bikeshed”,还有人接了句”先生,这里是 Wendy’s”。中途还岔出一段关于 Rails 的争论:smt88 说他亲眼见过两家发展不错的创业公司被 Rails 拖垮,xp84 斥之为”手艺差怪工具”,认为问题出在放任经验不足的开发者野蛮生长,Rails 完全可以负责任地使用。
社区氛围一如既往地轻松。 多位用户以”作为 HTMX 的 CEO”开头发言;有人发现发布配图和 Omarchy Quattro 的一样,作者立刻道歉说是从推特上拿的、不知道出处、已经撤掉;发现拼写错误 rething 被指出后,作者回:”这就是它不是 AI 生成的证据!谢谢!”