对 htmx 最常见的批评之一通常来自第一次听说它的人,如下所示:
你抱怨现代前端框架的复杂性,但你的解决方案只是另一个复杂的前端框架。
这是一个很好的反对意见!对于你引入到项目中的任何第三方 (3P) 代码,你都有权提出疑问。即使你没有亲自编写 3P 代码,但只要将其纳入项目,你就必须了解它–如果你想升级它,就必须重新了解它。
让我们将这些批评分解成其组成部分,并确定htmx在其声称要解决的伤害中到底有多少沉迷其中。
库和框架的区别
一些 htmx 捍卫者向我们求助:“htmx 不是一个框架,它是一个库。”这可能是不正确的。
“框架”是一个口语术语——对于某些第三方代码从“库”演变为“框架”的程度没有硬性规定——但我们仍然应该尝试定义它。在这种情况下:
- 库 - 3P 代码,其 API 不会显着影响应用程序的其余部分
- 框架 - 3P 代码,其 API 决定应用程序的整体结构
如果你更喜欢比喻:库是你添加到机器上的一个齿轮,框架是一个预先构建的机器,你可以通过自定义其齿轮来控制它。
这种区别虽然可能很模糊,但很重要,因为它描述了替换某些第三方代码的容易程度。例如,使用 CSV 解析库的 JavaScript 服务可能可以轻松地交换不同的 CSV 解析库;然而,使用 NextJS 框架的 JavaScript 服务可能在其整个使用寿命中都依赖于 NextJS,因为大量代码是在假设它与 NextJS 结构交互的情况下编写的。
因此,如果你的服务是在框架之上构建的,则其使用寿命与该框架的使用寿命相关。如果该框架被放弃,或被鄙视,或以其他方式不受欢迎,那么修改项目的难度将稳步增加,直到你放弃修改它,并最终将其完全封存。
这就是人们在问“htmx 只是另一个 JavaScript 框架吗?”时所担心的问题。他们希望确保自己不会致力于一个很快就会过时的系统,就像过去的许多 Web 开发框架一样。
那么:htmx是一个框架吗?它是否会很快被淘汰,在其迅速消亡后留下一系列无法维护的网站?
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 用于编写 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 成名之作:“churn”。根据你编写 React 应用程序的时间,你可能在编写表单时使用了受控类组件、react Hooks 或这种实验性的 <form>
扩展。这确实让人抓狂,尤其是如果你和我一样,最初是通过类组件学习如何制作网络表单的。
然而,无论你是何时编写的 htmx 应用程序,htmx 表单的行为都是以与普通 HTML 表单大致相同的方式定义的:使用 <form>
。随着 htmx 增加了额外的网络功能,你终于可以使用 PUT 请求并控制响应的去向,但在所有其他方面–验证、输入、标签、自动完成–你都只能使用默认的 <form>
元素行为。
最后,因为 htmx 只是在一个非常狭窄的域中扩展 HTML(网络请求和 DOM 替换),所以你编写的大多数“htmx”只是普通的旧 HTML。当你可以访问复杂的状态管理机制时,实现自定义可折叠 div 变得非常容易;如果不这样做,你可能会停下来足够长的时间来搜索 <details>
元素。每当问题可以通过本机 HTML 元素解决时,代码的寿命就会大大提高。这是一种学习 Web 开发的不太陌生的方式,因为只要 HTML 存在,你的大部分知识就将保持相关性。
在这方面,htmx 比 React 更像 jQuery(htmx 的前身 intercooler.js 是 jQuery 扩展),但它通过使用声明性的、基于 HTML 的界面对 jQuery 进行了改进:jQuery 让你转到 <script>
标签来指定AJAX行为,htmx只需要一个简单的 hx-post
属性。
简而言之,虽然 htmx 可以用作框架,但与 JavaScript 框架相比,它与 Web 语义的偏差要小得多,并且将受益于这些语义的改进,而无需用户进行额外的工作,这要归功于 Web 的出色性能向后兼容性保证。如果你想建立一个持续很长时间的网站,这些品质使 htmx 成为比许多同时代网站更好的选择。
注:尽管卡森(Carson)同意这一分析,认为这篇文章没有逻辑缺陷,并允许我在他的网站上发表,但他仍然坚持认为 htmx 是一个库。