首页 / 资讯中心 / 文章详情

何时使用超媒体:htmx 与 Hypermedia 架构的技术选型决策指南

何时使用超媒体:htmx 与 Hypermedia 架构的技术选型决策指南 ★ FEATURED ARTICLE
前端【免费下载链接】htmxhtmx - high power tools for HTML项目地址https://gitcode.com/GitHub_Trending/ht/htmx点击查看免费下载超媒体Hypermedia并非适合所有 Web 应用的银弹但它对大量以文本与图像为主、交互以 CRUD 为主、更新发生在明确定义区域内的应用有着压倒性的简化优势。本文以 htmx 官方博客文章《When Should You Use Hypermedia?》为核心骨架结合当前仓库中的示例与属性文档系统梳理超媒体架构的适用场景、不适用场景与过渡式Transitional混合开发策略帮助你在做功能级技术选型时获得可落地的判断依据。引言超媒体能解决什么代价又是什么在深入讨论何时使用超媒体之前有必要先明确 htmx 团队Carson Gross看待超媒体立场的基础——本文开头引用了 Roy Fielding 博士论文《Architectural Styles and the Design of Network-based Software Architectures》中关于 REST 统一接口的一段话The trade-off, though, is that a uniform interface degrades efficiency, since information is transferred in a standardized form rather than one which is specific to an applications needs. The REST interface is designed to be efficient for large-grain hypermedia data transfer, optimizing for the common case of the Web, but resulting in an interface that is not optimal for other forms of architectural interaction.翻译过来就是REST 的统一接口以牺牲效率换取通用性它针对大粒度超媒体数据传输这一 Web 的常见场景做了优化因此对其它形态的架构交互并非最优。这段话为全文定下了基调——超媒体有明确的优势边界选型应当基于权衡trade-off而不是信仰。在此基础上htmx 团队认为超媒体配合 htmx 带来的额外 UX 能力能够解决当前 Web 开发世界面临的许多问题具体体现为三大优势复杂度显著更低对于许多问题超媒体方案比 SPA 方案简单得多。参见仓库中的真实案例 《A Real World React → htmx Port》其中 Contexte 团队用 htmx 替换 React 后整体代码量减少了 67%。API 可被更激进地重构与优化因为超媒体应用通过 HTML 与服务器交互端点可以被频繁调整而不破坏客户端。这一论点在 《HATEOAS》 一文中有详细的理论展开。降低对特定服务器技术栈的绑定压力由于没有庞大的 JavaScript 前端代码库你不需要为了前端而被迫选择 Node.js 之类的后端技术可以自由使用 Python、Go、Java 等任何你熟悉的后端语言。正因如此作者相信借助 htmx 提供的额外 UX 可能性许多现代 Web 应用都可以用 HTML 与超媒体范式构建。但正如所有技术选择一样超媒体同样存在权衡本文接下来的全部内容就是帮助你在具体项目或功能上判断超媒体是否合适。过渡式应用Transitional Applications与超媒体在讨论什么时候超媒体是好选择之前必须先澄清一个前提构建 Web 应用时采纳超媒体并不是一个二选一either/or的决定。即便是最单页的单页应用SPA也必然使用超媒体——至少作为引导bootstrap机制来启动应用本身。Rich Harris 在其演讲Have SPAs Ruined The Web中提出了过渡式应用Transitional Applications这一术语指的是同时混合超媒体与非超媒体SPA概念的应用。htmx 团队在 《A Response To Have Single-Page Apps Ruined the Web?》 中对这场演讲做了详细回应核心立场是他们强烈认同过渡式这一务实的开发理念——应该为手头的具体工作选择正确的工具。双方真正的分歧点在于那条线划在哪里——即哪些功能适合用超媒体高效实现哪些功能需要更复杂的客户端方案。htmx 团队认为有了 htmx超媒体能覆盖的范围远比当今多数 Web 开发者认为的更大、更远对许多应用而言超媒体可以满足其全部或绝大部分 UX 需求。这一功能级feature-by-feature判断的思想贯穿全文也是结论部分的落点不要笼统地问htmx 适不适合我的应用而要问我的这个功能适不适合用超媒体实现。超媒体适合的场景你的 UI 以文本与图像为主在 《A Real World React → htmx Port》被作者称为 The Mother Of All htmx Demos中Contexte 公司的 David Guillot 展示了用 htmx 替换 React 之后总代码量减少 67%并伴随大量令人惊艳的指标JS 依赖减少 96%255 → 9、Web 构建时间减少 88%40 秒 → 5 秒、首次可交互时间TTI缩短 50%~60%、内存占用降低 46%。作者诚实地指出并非每个团队从 React 迁移到 htmx 都能获得这些结果Contexte 之所以如此契合超媒体是因为它是一个媒体导向的 Web 应用——展示由文本和图像构成的文章供用户阅读。它虽然拥有复杂的过滤机制等交互细节但应用的核心是展示与分类文章这正是超媒体被设计出来要做的事情。因此判断的第一条经验法则就是如果你的应用本质是读内容text image heavy超媒体几乎总是最优解。你的 UI 是 CRUD 型的超媒体在CRUDCreate, Read, Update, Delete型 Web 应用上拥有长期的成功记录典型代表是 Ruby on Rails 风格的应用。如果你的主要应用机制是展示表单、把表单保存进数据库超媒体可以工作得非常好。更重要的是配合 htmxCRUD 体验可以非常顺滑不再局限于许多服务端应用采用的列表页/详情页简单范式Click to Edit 示例点击编辑按钮通过hx-get/contact/1/edit无刷新地把详情视图替换为编辑表单提交时以hx-put/contact/1遵循 REST-ful 模式完成更新div hx-targetthis hx-swapouterHTML divlabelFirst Name/label: Joe/div divlabelLast Name/label: Blow/div divlabelEmail/label: joeblow.com/div button hx-get/contact/1/edit classbtn primary Click To Edit /button /divform hx-put/contact/1 hx-targetthis hx-swapouterHTML div labelFirst Name/label input typetext namefirstName valueJoe /div div classform-group labelLast Name/label input typetext namelastName valueBlow /div div classform-group labelEmail Address/label input typeemail nameemail valuejoeblow.com /div button classbtn typesubmitSubmit/button button classbtn hx-get/contact/1Cancel/button /formEdit Row 示例表格中的每一行都可以就地编辑。其核心技巧是hx-targetclosest tr hx-swapouterHTML——把请求的目标定位到触发元素最近的表格行整行替换tbody hx-targetclosest tr hx-swapouterHTML ... /tbody编辑态的行通过hx-includeclosest tr把整行输入框的值纳入请求参数HTML 规范不允许在tr内直接放置form这是表格场景的实用解法并通过hx-put提交保存tr hx-triggercancel classediting hx-get/contact/${contact.id} tdinput autofocus namename value${contact.name}/td tdinput nameemail value${contact.email}/td td button classbtn danger hx-get/contact/${contact.id}Cancel/button button classbtn danger hx-put/contact/${contact.id} hx-includeclosest trSave/button /td /tr从 hx-target 属性文档可以看到hx-target支持this当前元素自身、closest CSS selector向上查找最近的匹配元素如closest tr以及任意 CSS 选择器并且该属性可以放在父元素上被继承——这为 CRUD 场景提供了非常灵活的更新定位能力。你的 UI 是嵌套的更新大多发生在定义明确的块内超媒体开始站不稳的一个场景是UI 依赖关系跨越了屏幕的结构性区域。一个经常被提起的经典例子是 GitHub 的 Issues 标签页上的 issue 计数——很长一段时间里关闭一个 issue 后标签页上的计数没有正确更新。GitHub 大体上虽然不是绝对地采用了超媒体风格的应用。SPA 爱好者会欢呼看连 GitHub 都做不对这件事这个例子确实暴露了超媒体方法的一个问题如何干净地更新彼此分离disjoint的 UI 部分htmx 为此提供了多种手段详见 Updating Other Content 示例其中给出四种方案扩大目标expand the target、带外交换hx-swap-oob、触发自定义事件配合 HX-Trigger 响应头、以及 path-deps 扩展。Contexte 的演讲也提到他们用事件方式非常干净地处理了这类问题。但作者也坦承这是超媒体方法容易出问题的地方。规避该问题的一个潜在策略是把某个资源的相互依赖的元素在屏幕上放到同一个区域/范围内。举个具体例子假设一个联系人应用的详情页需要展示与编辑联系人包含三个区域基本信息区域姓名、姓氏等联系人的邮箱列表及邮箱数量联系人的电话号码列表及电话号码数量这个 UI 可以按如下方式布局在这种布局下每个子区域都可以拥有自己专属的超媒体端点/contacts/id/details—— 处理姓名、姓氏等信息/contacts/id/emails—— 处理邮箱区域/contacts/id/phonenumbers—— 处理电话号码区域其中的关键技巧在于邮箱数量和电话号码数量在屏幕上与其集合collection共处一地这样当集合被修改时可以用 hx-target 只针对那一块区域进行更新。所有数据依赖都被共置co-located在一个单一、简单、明确的更新目标内而且这些区域被替换时彼此互不干扰。每个区域实际上构成了一个独立的服务端组件彼此独立全部嵌套在一个更大的联系人详情 UI 之中。附注UI 驱动的超媒体 API注意这里的超媒体 API即我们的端点是由 UI 驱动的我们有一个想要达成的 UI 布局然后让 API 去适配它。如果 UI 变了我们会毫不犹豫地彻底改造 API 以满足新需求。这是超媒体开发中独特的一面作者在 《Hypermedia APIs vs. Data APIs》 中做了更深入的讨论——超媒体 API 的消息是自描述的self-describing因此 API 可以频繁变动而不破坏客户端这与必须严格版本化、保持稳定的数据 API如 JSON API形成鲜明对比。当然有些 UI 需求不允许把相互依赖的元素如此分组如果上文提到的那些技术扩大目标、OOB、事件、path-deps都无法令人满意那么可能就是时候考虑替代方案了。你需要深度链接与优秀的首次渲染性能超媒体优于其它方案的最后一个典型场景是你需要深度链接deep links——即能直接链接到应用落地页之外的内部页面——或者需要出色的首次渲染性能。超媒体是 Web 的天然语言浏览器在给定 URL 后渲染 HTML 的能力极强因此在传统 Web 特性如上两者上超媒体方法几乎无可匹敌。SPA 阵营常常引以为傲的可复制粘贴的 URL在 htmx 中通过 hx-push-url 等属性即可轻松获得同时天然保留浏览器后退/前进按钮与书签能力。超媒体不适合的场景你的 UI 存在大量动态的相互依赖正如上文嵌套 UI一节所讨论的当你的 UI 中存在大量散布于各处的依赖关系且无法承受整体刷新 UI的成本时超媒体就会遇到麻烦。这正是 Roy Fielding 在文首引言中所指出的Web 是为大粒度超媒体数据传输设计的而非为大量细碎的小型数据交换设计的。对超媒体尤其困难的是当这些依赖是动态的——即依赖那些在服务端渲染时无法确定的信息。最典型的例子是电子表格spreadsheet用户可以在任意单元格中输入任意函数从而在屏幕上动态引入各种依赖关系。不过作者也补充对许多应用而言Edit Row 示例中的可编辑行模式是更通用电子表格行为的可接受替代方案——它把编辑隔离在有限区域内与超媒体配合得很好。你需要离线功能超媒体分布式架构重度依赖服务端来渲染资源的表示。当服务器宕机或不可达时架构显然会遇到麻烦。虽然可以借助 Service Worker 处理离线请求但这是一个复杂的选项也可以像许多厚客户端应用那样轻易检测到超媒体应用处于离线状态并显示离线提示——但如果你的应用要求在离线环境中具备完整功能超媒体方法就是不可接受的。你的 UI 状态更新极其频繁另一种超媒体不适用的情况是UI 状态频繁更新。典型例子是需要捕捉鼠标移动的在线游戏在鼠标移动与 UI 更新之间插入一次超媒体网络请求是行不通的。这种情况下你应该为自己的游戏编写客户端状态管理并用其它技术与服务器同步。但注意作者特别强调你的游戏可能也有一个设置页而那个设置页用超媒体做可能比你为游戏核心选择的方案更好。在过渡式风格下混合使用不同方法完全没问题。作者还补充了一个重要的可操作性观察通常把 SPA 组件嵌入更大的超媒体架构中比反向操作更容易。孤立的客户端组件可以通过事件与更广泛的超媒体应用通信——正如 Sortable.js 拖拽排序 htmx 示例所演示的用htmx.onLoad初始化 Sortable 实例以hx-triggerend监听拖拽结束事件并hx-post/items提交新顺序同时在htmx:afterSwap事件后重新启用排序htmx.onLoad(function(content) { var sortables content.querySelectorAll(.sortable); for (var i 0; i sortables.length; i) { var sortable sortables[i]; var sortableInstance new Sortable(sortable, { animation: 150, ghostClass: blue-background-class, filter: .htmx-indicator, onMove: function (evt) { return evt.related.className.indexOf(htmx-indicator) -1; }, onEnd: function (evt) { this.option(disabled, true); } }); sortable.addEventListener(htmx:afterSwap, function() { sortableInstance.option(disabled, false); }); } })form classsortable hx-post/items hx-triggerend div classhtmx-indicatorUpdating.../div divinput typehidden nameitem value1/Item 1/div divinput typehidden nameitem value2/Item 2/div divinput typehidden nameitem value3/Item 3/div divinput typehidden nameitem value4/Item 4/div divinput typehidden nameitem value5/Item 5/div /form你想要开箱即用的复制粘贴组件近年来出现了大量Copy Paste友好型组件例如 ShadCN。这些组件通常为 React 等特定前端框架设计选择 htmx 意味着你无法使用它们。虽然也存在框架中立的组件库如 lit但它们与 htmx 的集成度远不及 ShadCN 与 React 的集成度。如果你的团队高度依赖这类生态组件这一点需要在选型时纳入考量。你的团队不买账最后一个不建议选择超媒体的原因不是技术性的而是社会性的sociological当前超媒体在 Web 开发界并不流行。许多公司已把 React 作为构建 Web 应用的标准库许多开发者与顾问把自己的职业生涯押注其上许多招聘经理从未听说过超媒体、更别说 htmx却出于习惯在每份招聘启事上写上 React——招聘显然容易得多。作者承认这令人沮丧但这是一个真实存在的现象应当以谦逊的态度正视虽然 Contexte 能够快速高效地用 htmx 重写他们的应用但并非每个团队都如此小而敏捷、充满热情也不是每个应用都是该方法的灌篮slam dunk。务实的建议是先在边缘地带采用超媒体——也许先从内部工具开始——在证明其价值之后再考虑更大范围的推广。结论把问题从应用级细化到功能级作者经常被问到那么什么样的应用不适合htmx 他们更倾向于使用过渡式应用概念、以**功能为单位feature-by-feature**来思考问题但脑海中保留一些广为人知的应用作为参照有助于判断超媒体与其他方法各自能覆盖多少。适合超媒体实现的知名应用例子Twitter与GMail。两者都是文本与图像密集、粗粒度更新的 Web 应用非常适合超媒体方法。不适合超媒体实现的知名应用例子Google Sheets与Google Maps。Google Sheets 的许多单元格之间存在大量状态与相互依赖不可能对每次单元格更新都发起服务器请求Google Maps 则需要对鼠标移动做出快速响应同样无法承受每次移动都经历一次服务器往返。这两者都需要远比超媒体所能提供的更复杂的客户端方案。当然绝大多数 Web 应用都远未达到这些例子的规模与复杂程度。而且几乎每个 Web 应用——即便是 Google Sheets 或 Google Maps——都有一些部分可能更适合超媒体方法更简单、更快、更干净。把超媒体纳入你的工具箱会提升你作为 Web 开发者解决工程问题的能力——即便它不会成为你最爱的那把锤子。这里有扎实的理论基础有对许多应用的实践收益并且它在某种意义上顺着 Web 的纹理with the grain of the web行事而这正是其它方法所不具备的。进一步阅读仓库内资源架构总览《Hypermedia-Driven Applications》 —— HDA 架构的定义与示例片段如 Active Search 示例理论基石《HATEOAS》、《Hypermedia APIs vs. Data APIs》实践案例《A Real World React → htmx Port》交互示例Click to Edit、Edit Row、Updating Other Content、Sortable属性文档hx-target、hx-swap-oob、hx-include核心实现htmx 源码 与类型声明 位于仓库src/目录测试用例位于 test/ 目录可对照验证上述属性的实际行为赞分享前端【免费下载链接】htmxhtmx - high power tools for HTML项目地址https://gitcode.com/GitHub_Trending/ht/htmx点击查看免费下载相关推荐htmx Essays 全览一份围绕超媒体Hypermedia与 REST 思想体系构建的官方文章索引htmx Essays 全览一份围绕超媒体Hypermedia与 REST 思想体系构建的官方文章索引 导读htmx 官网的 Essays 栏目位于仓前端sealos技术选型架构决策与技术栈sealos技术选型架构决策与技术栈 引言云原生时代的架构革命 在云原生技术蓬勃发展的今天传统的云计算架构正面临着前所未有的挑战。复杂的部署流程、高昂的学云原生后端前端使用 API Blueprint 描述超媒体 APIPolls Hypermedia API 实战范本使用 API Blueprint 描述超媒体 APIPolls Hypermedia API 实战范本 API Blueprint 是一套建立在 Markdo文档API设计教程上一篇5分钟掌握Windows虚拟串口神器com0com完全免费使用指南下一篇3个步骤让猫抓浏览器插件帮你轻松捕获任何网页视频资源创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站