Rich Harris是一位知名的Web开发人员,致力于Svelte.js的开发,这是一个新颖的单页应用(SPA)框架。
2021年10月,他在JamStack上发表了一场题为"单页应用是否毁了Web?"的演讲。
有人询问我们对这场演讲的看法,因此本文就是我们的回应。
关于这场演讲首先要说的是它做得非常好:制作精良、深思熟虑、幽默、对辩论双方都很公平,并且整个过程非常合理。我们不同意Harris先生的许多观点,如下文所述,但我们尊重并欣赏他的观点以及他所从事的技术。
演讲以对SPA的一些合理批评开始,特别关注了Instagram(来自Facebook的朋友们的一个典型SPA实现)中发现的可用性问题。他非常公正地看待了SPA的缺点,包括但不限于以下列表:
在考虑了Instagram的可用性问题后,Harris先生这样说:
拜托各位。如果世界上最优秀的前端工程师都无法在没有5兆字节JavaScript的情况下让文本和图像正常工作,也许我们应该放弃Web平台。
在这里,我们与Harris先生达成了强烈共识,但有一个前提:我们会将"Web平台"替换为"JavaScript Web平台",因为Instagram的情况正是如此。
我们进一步澄清,SPA应用和框架通常只是简单地忽略了真正的Web平台,即Web原始的、REST风格模型,除了作为引导机制。
Harris先生接着讨论了多页应用(MPA)的问题,这是我们熟悉的"传统"、点击链接加载HTML页面的Web应用,在某种程度上正在被SPA取代。
下面,我们将逐一讨论他概述的各种问题,所有这些问题都是"标准"MPA的真实问题,并且我们将展示使用超媒体导向技术htmx的MPA如何解决每个问题。
标准MPA的一个普遍问题是它们在每次请求时都会进行完整的页面刷新。这意味着像视频或音频播放器这样的内容会在请求时被替换,从而停止播放。
这个问题可以通过htmx的hx-preserve
属性来解决,该属性告诉htmx在请求之间保留特定的内容片段。
在存在无限滚动行为(大概通过某种JavaScript实现)的情况下,后退按钮无法与MPA正常工作。我会注意到无限滚动的存在让人质疑MPA这个术语,传统上MPA会使用分页而不是无限滚动。
也就是说,无限滚动可以很容易地使用htmx实现,以一种超媒体导向且明显的方式。当与hx-push-url
属性结合使用时,历史和后退按钮只需很少的开发工作就能正常工作,并且都有可复制粘贴的URL,有时被SPA社区的人称为"深度链接"。
漂亮的过渡确实很好。但我们认为设计师往往高估了它们对应用可用性的贡献。是的,演示很炫酷,但在第20次点击时,用户通常只希望UI继续工作。
也就是说,htmx支持使用标准CSS过渡来实现动画。显然,这些纯CSS技术能实现的效果有限,但我们相信这可以让你达到80/20情况中的80。(或者可能是95/5情况中的95。)
Harris先生将"糟糕的广告技术"作为Web可用性问题的罪魁祸首,谁能为今天大多数网站向用户提供的2.5MB跟踪、间谍软件和广告软件的负载辩护呢?Harris先生指出,SPA通过一次性加载这堆垃圾而不是像MPA那样每次请求都加载,从而缓解了这个问题。
现在,普通的MPA通常会在第一次请求后缓存这堆垃圾,因此下载成本至少与SPA相同。但MPA必须在每个页面上再次执行这堆垃圾,这确实会消耗CPU并可能导致糟糕的用户体验。
然而,我们注意到,由htmx驱动的MPA具有与SPA完全相同的特性:广告垃圾会在第一次请求时下载并执行一次,之后所有请求都将是相对轻量级的DOM元素替换。
这是一个合理的观点:使用MPA风格的应用程序,你的UI交互受限于服务器响应请求的速度,即其延迟。其中一部分是网络延迟,如果不放弃传统Web应用程序的一个极大简化方面:集中式数据存储,就很难克服。然而,网络速度很快并且越来越快,并且有众所周知的优化服务器延迟(即服务器返回响应的速度)的技术,经过几十年的发展,用于监控和优化这个响应时间。SQL调优、Redis缓存等等,都使得低于100毫秒的响应成为一个合理的目标。许多htmx用户评论说基于htmx的应用程序感觉多么快速,但我们不会假装延迟不是一个需要考虑的问题。
当然,延迟问题的关键在于它会让应用感觉迟缓。但是,像你一样,我们也使用过许多迟缓的SPA,所以我们必须说这个问题并不能简单地通过采用SPA框架来解决。除此之外,乐观地与服务器同步数据可能导致极难理解的数据一致性问题,以及整体应用复杂性的显著增加,这个话题我们稍后会再讨论。
GitHub确实有UI错误。然而,它们都不是特别难解决。
htmx提供了多种方法来更新目标元素之外的内容,所有这些方法都非常简单,任何方法都可以解决Harris先生指出的UI一致性问题。
将GitHub的UI问题与Harris先生之前指出的InstagramUI问题进行对比:Instagram的问题需要更复杂的工程工作来解决。
Harris先生随后讨论了"过渡性应用"的概念,即SPA和MPA技术的混合体。这个术语是合理的,我们将看看这个术语是否会在行业中流行。
我们经常建议在适合保持简单的地方使用htmx,然后在需要时使用其他技术:alpine.js、hyperscript、一个小型响应式框架等。
因此,我们可以在一定程度上同意Harris先生的观点,并推荐一种"过渡性"的Web开发方法,尽管我们会尽可能倾向于MPA/超媒体,而Harris先生似乎肯定会倾向于SPA/JavaScript。
不幸的是,有一个话题Harris先生没有讨论,我们认为这可能是因为他没有看到它。他是一位对JavaScript充满热情的JavaScript开发人员,沉浸在前端框架的工程文化中,因此当前JavaScript前端开发的复杂性对他来说似乎是自然的。然而,对我们许多人来说,JavaScript生态系统简直疯狂地过于复杂。事实上,考虑到大多数Web应用的需求,这很可笑。
Harris先生随后提到的许多"过渡性"技术:React服务器组件(他称之为"像HTML over the wire,但复杂得多")、Marko(正在进行"部分水合")、Quik(显然积极懒加载东西),都是了不起的工程成就,但我们也必须说,它们都非常复杂。
不幸的是,这是当前前端开发文化的一部分:在应用框架、构建工具链、部署模型等方面容忍极高的复杂性,而当所有这些复杂性导致问题时,通常会用更多的复杂性作为答案。
"简单"被轻视,而"复杂"则备受赞誉。
这种复杂性正在压倒许多开发人员和开发团队。正如Harris先生在讨论Instagram时指出的那样,即使是世界上一些最优秀的前端工程师似乎也无法控制这一切。
所以这里有一个文化问题。
也有一个技术问题。
这个技术问题可以概括为"超媒体方法"与"远程过程调用(RPC)方法"。
当Web应用从MPA转向SPA时,它们往往无意中采用了RPC方法进行应用开发:AJAX转向JSON作为数据序列化格式,并基本上(并且正确地)放弃了超媒体的概念。这种对超媒体方法的放弃是由普通MPA公认的可用性问题驱动的。
然而,事实证明,这些可用性问题通常可以通过超媒体方法解决:与其放弃超媒体转向RPC,我们当时和现在需要的是一个更强大的超媒体。
这正是htmx提供的。
通过回归超媒体方法,你可以构建相当复杂的Web应用,以解决Harris先生关于MPA的许多担忧,而所需复杂性只是大多数流行SPA框架的一小部分。此外,无需过多思考,你将获得Roy Fielding概述的真正REST架构的所有好处。
超媒体架构是否适合所有Web应用?显然不是。
它是否适合许多,也许是大多数Web应用?我们当然这么认为,至少部分适用。
现在我们来到演讲中最情绪化的主张:关于JavaScript的"船已经起航",我们应该接受它将成为未来Web开发中的主导编程语言。
Harris先生认为,边缘计算将成为最终消除剩余、分散的对JavaScript抵制的驱动力。
我们对此不太确定。
相反,我们不认为边缘计算会在可预见的未来(或者坦率地说,永远)在大多数Web应用中发挥作用。CPU很便宜,网络速度很快并且在提高,微服务是一团糟。
而且,与Harris先生所说的相反,今天趋势显然不利于JavaScript。五年前,作为JavaScript抵抗运动的创始成员,我们对阻止JavaScript巨轮感到绝望。但随后发生了意想不到的事情:Python起飞了,与此同时,JavaScript停滞不前:
这种JavaScript在2010年代中期达到顶峰的趋势也可以在GitHub上观察到:
现在,这是否意味着JavaScript最终会"输给"Python并消失?
当然不是。JavaScript是Web的核心技术,将永远与我们同在。没有它,我们就无法构建htmx(或hyperscript),因此我们非常感谢JavaScript。
但这确实意味着Web的未来并不必然完全属于JavaScript,就像五年前看起来的那样。
我们喜欢谈论HOWL堆栈:Hypermedia On Whatever you'd Like(超媒体随你所好)。这个想法是,通过回归(更强大的)超媒体架构,你可以使用任何你喜欢的后端语言:python、lisp、haskell、go、java、c#,随便什么。如果你喜欢,甚至可以是JavaScript。
由于你使用超媒体和HTML进行服务器交互,你不会感受到大型JavaScript前端带来的在后端采用JavaScript的压力。当然,你仍然可以使用JavaScript(可能以alpine.js的形式),但你以它最初设计的方式使用它:作为一种轻量级的前端脚本语言,用于增强你的应用。或者,如果你勇敢,也许可以尝试hyperscript来满足这些需求。
这是我们更愿意生活的世界:多种编程语言选择,每种都有自己的优势、技术文化和繁荣的社区,都能通过更强大的超媒体的魔力参与Web开发世界,而不是SPA-用-JSON-与-Node-对话的单一文化。毕竟,多样性是我们的力量。
最后,