← 文章 / 编程开发
Hacker News 5小时前 · 2026-08-29 02:16:00 · 2 阅读

htmx 4.0.0 正式发布

htmx 团队非常高兴地宣布 htmx 4.0.0 正式发布!这是 8 个月工作(外加一个游戏)的结晶,我们对结果非常满意。

htmx 4 的想法开始萌芽,是在我决定创建 fixi 的时候,借此我对 fetch() API 和 JavaScript 异步编程变得更熟悉了。(出于向后兼容的考虑,htmx 一直使用 XMLHttpRequest。)

一个偶然的晚上,Christian 联系了我,他对流式 HTML有一些有趣的想法,这让我开始思考:把内部实现迁移到 fetch() 会让他的场景乃至整个库都更简单。
经过一番工作,我说服了 Michael 和 Alex 加入,我们便一发不可收拾。

开发过程非常顺利。我们从移植 fixi 和 htmx 测试套件开始。随着时间推移,我们不断重新理解 htmx 当初为什么那样设计,并让新实现一步步向旧实现靠拢。现在 2.x 与 4.x 的行为差异已经相对较小,而在确实存在分歧的地方,我们都做出了明确取舍,让基于 htmx 的应用有良好基础去成为百年 Web 服务

请注意,我们没有在 NPM 上把 4.0 标记为 latest,因为不想强迫升级那些依赖无版本号 CDN URL 的用户。2.x 将继续作为 latest,4.0 线将保持 next,直到 2027 年初的某个时点。不过官网会指向 4.0。

主要变化

如上所述,从用户视角看,htmx 4 与 htmx 2 几乎完全相同。主要有三个变化:

  • 属性继承默认从「隐式」改为「显式」(这是升级中最重要的一项)
  • htmx 事件名称已标准化并做了清理。部分高级用户可能需要修改自己监听的事件。
  • 历史支持默认不再使用 localStorage(这曾是许多支持难题的根源)。大多数人完全不会注意到这一点。

在内部,我们从 XMLHttpRequest 迁移到了 fetch(),但这对大多数 htmx 用户应当是透明的。

属性继承

在 htmx 2 中,很多属性默认是「可继承」的:把属性放在父元素上,其行为会应用到子元素。这一行为源自 intercooler.js 时代,灵感来自 CSS,而效果也和 CSS 差不多:强大,但有时难以理解。

在 htmx 4 中,属性默认不再继承,除非你在属性名后面加上 :inherited 显式声明

<!-- htmx 2 -->
<div hx-confirm="Are you sure?">
    <button hx-delete="/item/1">Delete</button>
</div>

<!-- htmx 4 -->
<div hx-confirm:inherited="Are you sure?">
    <button hx-delete="/item/1">Delete</button>
</div>

这将是从 htmx 2 迁移到 htmx 4 时最大的升级负担。为了让事情容易些,我们提供了一个命令行工具,帮你找出需要标记为 inherited 的位置。

注意,hx-disinherit 之类的属性不再需要,应当移除。

事件

htmx 2 触发的事件是随库的生命周期自然生长起来的,组织得并不好,很难搞清楚哪个事件在何时触发。

在 htmx 4 中,所有事件都遵循 htmx:phase:action[:sub-action]

htmx 2htmx 4
htmx:beforeRequesthtmx:before:request
htmx:afterRequesthtmx:after:request
htmx:beforeSwaphtmx:before:swap
htmx:afterSwaphtmx:after:swap
htmx:configRequesthtmx:config:request

此外还有以下变化:

  • 大多数错误事件合并为 htmx:error。HTTP 错误响应会触发 htmx:response:error
  • htmx:xhr:* 系列事件已移除。htmx 4 使用 fetch()
  • htmx:validation:* 系列事件已移除,改用浏览器原生表单校验。

完整对照表见 What's New in htmx 4

命令行升级检查器能在 hx-on 属性以及它能找到的 JavaScript 中标记出旧事件名。

历史

htmx 一直内置历史支持,让你用简单属性实现感知浏览器后退按钮的交互。在 htmx 2 中,它用 localStorage 里的缓存对页面做快照以便恢复。可惜一个主要的问题来源是:快照可能包含第三方 JavaScript 库造成的 DOM 修改。页面恢复时,那些修改还在,但其背后的 JavaScript 逻辑却不在了。

htmx 4 不再把页面缓存到 localStorage。后退导航时,htmx 会重新请求页面并把它换入 <body>,若存在 [hx-history-elt] 元素则换入该元素。这让第三方 JavaScript 库在大多数情况下「直接可用」,而且配合良好的请求缓存,速度非常快。

如果你想要本地缓存,我们如今附带了一个非常完善的 hx-history-cache 扩展,从 sessionStorage 恢复历史,并且设计为能与 Alpine.js 等脚本方案良好集成。

新特性

htmx 4 有两个令人兴奋的大型新特性:

Morph 交换

htmx 现在开箱即用地支持 morph 交换。我创建了 idiomorph,当年差点把它并入 htmx 2.x,后来还是放弃了。在 htmx 4 中,Michael 在该算法上做了出色改进,并将其无缝集成进 htmx。

<hx-partial>

另一个重要的新特性是 <hx-partial> 标签。它与带外交换(out-of-band swaps)类似,但当你想做的不仅仅是「把单个元素替换成自己的新版本」时,它的表达清晰得多:

<hx-partial hx-target="#messages" hx-swap="beforeend">
    <div>New message</div>
</hx-partial>
<hx-partial hx-target="#count">
    <span>5</span>
</hx-partial>

扩展

htmx 4 令人兴奋的地方很大程度在扩展上。内部改用 fetch() 让我们得以重新思考扩展可以并且应该怎样工作,也催生(或重造)了许多新扩展,例如:

  • hx-preload —— 预加载内容(例如在 mouseover 时)以加快请求
  • hx-download —— 基于原生 fetch 的文件下载
  • hx-alpine-compat —— 化解 htmx 与 Alpine.js 之间的兼容性问题
  • hx-history-cache —— 将历史缓存到 sessionStorage,并提供 Alpine.js 兼容性

此外,还有三个新的或更新的流式 HTML 扩展:

  • hx-sse 通过 text/event-stream 流式传输。
  • hx-ws 通过 WebSocket 流式收发。
  • hx-multipart 通过 multipart/mixed 流式传输。

最后,我们觉得是时候亲手做一个与 htmx 紧密集成的轻量前端脚本方案了。hx-live 的灵感来自 Alpine.js、jQueryhyperscript,让前端脚本编写变得愉快而有趣。它甚至支持我们所说的基于 DOM、对 HATEOAS 友好的响应式。

发行包中还有一个新的 htmax.js 捆绑包,把 htmx 与其中最受欢迎的扩展打包进单个文件——如果你不想纠结选哪些的话。

升级

完整的升级指南见 What's New in htmx 4

如前所述,我们提供了一个升级工具来帮助你:

$ npx htmx.org@4.0.0 upgrade-check -- ./templates

File extensions: .html, .php, .js, .ts, .jinja, .jinja2, .j2, .erb, .hbs
Use --ext to add more (e.g. --ext .vue --ext .svelte)

Scanning 1 file(s)...

Found 8 issue(s) in 1 of 1 file(s).
templates/index.html:1: [inheritance] hx-headers needs :inherited suffix (descendant on line 3 has hx-delete) (this looks like a CSRF token; without :inherited the header does not reach child elements and the server rejects the request)
templates/index.html:2: [inheritance] hx-target needs :inherited suffix (descendant on line 3 has hx-delete)
templates/index.html:2: [inheritance] hx-confirm needs :inherited suffix (descendant on line 3 has hx-delete)
templates/index.html:3: [renamed-attr] hx-disable -> rename to hx-ignore (hx-disable now means 'disable during request')
templates/index.html:4: [removed-attr] hx-vars is removed -> use hx-vals with js: prefix
templates/index.html:4: [removed-attr] hx-prompt is removed -> load the hx-prompt extension to keep the same syntax
templates/index.html:9: [old-event] old event name "htmx:afterRequest" -> "htmx:after:request"
templates/index.html:9: [old-api] htmx.addClass() is removed -> use element.classList.add()

我们还随版本发布了一个 agent skill 来辅助升级

安装

htmx 4.0 可以通过包管理器指定版本 4.0.0 安装,也可以通过 CDN 引入:


<script src="https://unpkg.com/htmx.org@4.0.0/dist/htmx.min.js"></script>

或者直接下载

LLM

不管你喜不喜欢,很多人都在用 LLM,为此我们提供以下 skills 文件:

(在 LLM 时代发布库的新版本究竟是好事还是坏事,这个话题就先放到一边吧!)

结语

希望你喜欢 htmx 4。htmx 2 将无限期继续获得支持,所以不必有升级压力。

我要感谢以下人士在本次发布中提供的所有帮助:

  • Michael West —— 了不起的队友、grug 头脑的开发者
  • Christian Tanul —— 启发了 htmx 4,并主导流式与 live 扩展
  • Alex Petros —— 让这艘船始终保持平稳
  • Stephen Mitchell —— 那个游戏背后的天才
  • Stu Kennedy —— 我们的 WebSocket 专家
  • André Ahlert Jr. —— 提供 IDE 与编辑器支持
  • Dien Hoa Truong —— 早期试用 htmx 4 并帮忙修复了许多 bug

升级音乐

没有升级音乐的 htmx 更新是不完整的:

原始来源: Hacker News

评论 (0)