对 htmx 最常见的批评之一,通常来自第一次听说它的人,是这样的
你抱怨现代前端框架的复杂性,但你的解决方案仅仅是另一个复杂的前端框架。
这是一个极好的反对意见!这是关于你在项目中引入的任何第三方 (3P) 代码都要问的正确问题。即使你没有自己编写 3P 代码,但通过将其包含在你的项目中,你就承诺要理解它——如果你想升级它,也要刷新对它的理解。这是一个很大的承诺。
让我们将这种批评分解成其组成部分,并确定 htmx 在多大程度上沉迷于它声称要解决的弊端。
一些 htmx 的拥护者跳出来帮我们: “htmx 不是框架,它是一个库。” 这可能是不正确的。
“框架”是一个口语化的术语——对于一些第三方代码从“库”演变成“框架”的临界点,没有硬性规定——但我们仍然应该尝试对其进行定义。在此背景下
如果你喜欢比喻:库是你添加到机器中的一个齿轮,框架是你通过定制其齿轮来控制的预制机器。
这种区别,尽管它可能很模糊,但很重要,因为它描述了某些第三方代码被替换的难易程度。例如,使用 CSV 解析库的 JavaScript 服务可能可以在不造成太大麻烦的情况下切换到另一个 CSV 解析库;但是,使用 NextJS 框架的 JavaScript 服务可能在其整个使用寿命期间都依赖于 NextJS,因为很大一部分代码是在假设它正在与 NextJS 结构交互的情况下编写的。
因此,如果你的服务构建在框架之上,其有效寿命将与该框架的有效寿命绑定。如果该框架被放弃、被鄙视或变得不受欢迎,修改你的项目的难度会稳步增加,直到你放弃修改它,最终,完全将其束之高阁。
这就是人们在问“htmx 仅仅是另一个 JavaScript 框架吗?”时所担心的问题。他们想要确保自己不会承诺于一个很快就会过时的系统,就像过去许多 Web 开发框架一样。
所以:htmx 是一个框架吗?它会很快被淘汰,在其迅速消亡之后留下无数无法维护的网站吗?
向我们社区关于这个问题的持续辩论致歉——我认为 htmx 很明显是一个框架,至少在大多数用例中是如此。但这确实取决于你如何使用它。
无论你在项目中使用 htmx 的哪个地方,你都在你的 HTML 中包含 htmx 属性(即 hx-post
、hx-target
),编写使用 htmx 格式化数据调用的端点(具有某些请求标头),并从这些端点返回 htmx 期望的格式化数据(带有 hx-*
控制的 HTML)。所有这些属性、标头和端点相互交互,形成一个系统,通过该系统,元素通过网络请求进入和退出 DOM。
如果你使用 htmx 来处理网站相当一部分的网络请求,那么 htmx 包含在你的应用程序中,将对项目的结构产生重大影响,从你构建前端标记的方式,到你的端点执行的数据库查询。这是类似于框架的行为,在这种情况下,htmx 无法轻易被替换。
你当然可以用类似库的方式使用 htmx,为网页的某些部分添加动态功能。但是,你也可以用这种类似库的方式编写React,而且没有人会争辩说 React 不是框架。足以说明,许多在他们的应用程序中使用 htmx 的人,都是以一种屈服于 htmx 要求的方式使用它,将其作为一个构建超媒体应用程序的框架。
他们应该这样做!如果发挥 htmx 的优势,使用 htmx 构建会好得多。你可以发送 JSON 格式的表单主体,如果你真的坚持。但你不应该这样做!仅仅使用 application/x-www-form-urlencoded
主体,并编写一个接受它们的端点,会更简单。你可以编写一个在多个不同客户端之间重用的端点,如果你真的坚持。但你不应该这样做!更简单的方法是将你的数据和超媒体 API 分成单独的 URL。没错,htmx 可以用作库,但也许可以让它也成为你的框架。
然而,这并不意味着 htmx 仅仅是另一个 JavaScript 框架,因为 htmx 具有其他框架所不具备的一个巨大优势:HTML。
假设你使用 htmx 作为框架——它是一个JavaScript框架吗?从一个明显的意义上说,是的:htmx 用大约 4k 行 JS 实现。但在另一个更重要的意义上,它不是:React、Svelte、Solid 等等让你编写 JS(X),该框架将其转换为 HTML;htmx 只是让你编写 HTML。这消除了可能随着时间的推移而导致你放弃其他框架的整个维护类别。
当你想要升级或更改某个依赖项,但你使用的框架与该更改不兼容时,代码库往往会陷入僵局。Java 在这里是最臭名昭著的违规者——生产环境中有无数行的 Java 代码永远不会离开 Java 8,因为升级 Spring 太难了——但 npm 包生态系统紧随其后。当你使用 htmx “框架”时,你永远不会遇到这个问题,因为 htmx 是一个零依赖、客户端加载的 JavaScript 文件,所以它保证永远不会与你的服务器确实依赖的任何构建过程或依赖项链发生冲突。
浏览器渲染 HTML,因此永远不需要编译器或转译器来使用 htmx。虽然许多 htmx 用户乐于使用 JSX 渲染 API 响应,但 htmx 与经典模板引擎配合得非常好,使其可移植到你喜欢的任何语言。不论你对 Django 和 Rails 有何评价,它们在 2008 年很流行,今天也很流行——htmx 与它们都能无缝集成。这是 htmx 驱动的开发的反复出现的主题:htmx 与新旧开发工具都能很好地配合,因为所有这些工具的共同点是 HTML,而 htmx 用于编写 HTML。
迫使用户主要在 HTML 而不是 JS 中定义其应用程序的行为,其优势太多,在本篇文章中无法一一列举,因此我将重点介绍人们最讨厌 JavaScript 框架的一点:快速迭代。根据你编写 React 应用程序的时间,你可能使用受控类组件、React hooks或这个实验性的 <form>
扩展编写了表单。这确实让人抓狂,尤其是如果你——像我一样——最初学习使用类组件制作 Web 表单时。
然而,无论何时编写 htmx 应用程序,htmx 表单的行为始终以与普通 HTML 表单基本相同的方式定义:使用 <form>
。有了 htmx 添加的额外网络功能,你终于可以使用 PUT
请求并控制响应的去向,但在所有其他方面——验证、输入、标签、自动完成——你都有默认的 <form>
元素行为。
最后,由于 htmx 只是在一个非常狭窄的领域(网络请求和 DOM 替换)扩展了 HTML,因此你编写的大部分“htmx”只是普通的 HTML。当你可以使用复杂的状态管理机制时,实现自定义可折叠 div 非常容易;当你不能时,你可能会停下来搜索<details>
元素。每当可以用原生 HTML 元素解决问题时,由于其结果,代码的持久性会大大提高。这是一种不那么让人疏远的学习 Web 开发的方式,因为你的大部分知识只要 HTML 存在,就会一直保持相关。
在这方面,htmx 更像 JQuery 而不是 React(htmx 的前身,intercooler.js,是 JQuery 的扩展),但它通过使用声明性的、基于 HTML 的界面改进了 JQuery:JQuery 让你去 <script>
标签中指定 AJAX 行为,而 htmx 仅仅需要一个简单的 hx-post
属性。
简而言之,虽然 htmx 可以用作框架,但它是一个与 Web 语义偏离程度远低于 JavaScript 框架的框架,并且由于 Web 的出色的向后兼容性保证,它将受益于这些语义的改进,而无需用户做任何额外的工作。如果你想要构建一个可以持续很长时间的网站,这些特性使 htmx 比它的许多同行更具优势。
注意:尽管同意这种分析,在文章中没有发现逻辑上的缺陷,并允许我在他的网站上发表,但卡森仍然坚持认为 htmx 是一个库。