ESC
开源 2 分钟阅读

Htmx 4.0 发布

htmx 4.0 正式发布,带来多项重大变更:属性继承需显式声明、事件命名规范化、历史记录不再使用 localStorage 缓存,并新增 morphing swaps 和 <hx-partial> 标签。同时提供命令行升级检查工具,方便迁移。

来源:Hacker News

在 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 4 时最大的升级负担。为了简化这一过程,我们提供了一个命令行工具来帮助你找到需要标记为继承的位置。

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

htmx 2 触发的事件在库的发展过程中自然增长,组织得不是特别好,导致很难确切知道何时触发了哪个事件。

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

此外,还做了以下更改:

完整表格请参阅《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 有两个我们非常兴奋的重大新特性:

我们现在在 htmx 中原生支持 morphing swaps。我创建了 idiomorph,差点把它包含在 htmx 2.x 中,但最终决定不这样做。在 htmx 4 中,Michael 对算法进行了出色的改进,并将其无缝集成到 htmx 中。

另一个主要新特性是 <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() 让我们得以重新思考扩展如何工作以及应该如何工作,并催生了许多新扩展的创建(和重新创建),例如:

此外,还有三个新的或……

最后,我们决定是时候尝试我们自己的、与 htmx 紧密集成的小型前端脚本解决方案了。hx-live 的灵感来自 Alpine.js、jQuery 和 hyperscript,让前端脚本编写变得愉快而有趣。它甚至支持我们所说的基于 DOM、HATEOAS 友好的响应式。

发行版中新增了一个 htmax.js 捆绑包,如果你不想考虑选择哪些扩展,它将 htmx 与其中最流行的扩展打包在单个文件中。

完整的升级指南请参阅《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 来协助升级。