2022 年 JavaScript 网站构建模式
如今,选择合适的方法和工具来构建 Web 应用可能颇具挑战性。市面上有很多不同的选择,它们都声称自己是最好的,而且往往以看似相互矛盾的方式进行。
奇怪的是,他们并没有错。网络上有很多不同类型的体验,从简单的商业列表页面到在浏览器中运行AutoCAD。
但即使知道网络广阔而多元,我们仍然希望解决方案的数量不要和网站的数量一样多。虽然一刀切的方案可能不现实,但或许有办法减少一些混乱。通过对所使用的技术进行分类,我们就能找到讨论它们的方式,并进行有意义的比较。
对我来说,有效的框架是带着三个问题来看待这个问题:
- 您导航到哪里?
- 什么时候渲染?
- 如何补水?
没有唯一正确的答案。不同的场地有不同的需求。那么,我们如何才能让这个问题更加具体呢?
我们可以看看 UI 框架,但它们是一个不断变化的目标,不断更新和改进。当你读到这篇文章的时候,它就已经过时了。或许最好用原型来讨论这个问题(借鉴 Jason Miller 的《应用程序全息类型》)。
文件夹 | 内容 | 店面 | 社交网络 | 沉浸式 | |
---|---|---|---|---|---|
正模标本 | 个人博客 | 美国有线电视新闻网 | 亚马逊 | Figma | |
交互性 | 最小 | 相关文章 | 购买 | 多点、实时 | 一切 |
会话深度 | 浅的 | 浅的 | 浅 - 中 | 扩展 | 深的 |
价值观 | 简单 | 可发现性 | 负载性能 | 动态主义 | 沉浸感 |
路由 | 服务器 | 服务器,HTML交换 | HTML 交换,混合 | 混合型,客户端 | 客户 |
渲染 | 静止的 | 静态,SSR | 静态,SSR | 苏维埃社会主义共和国 | 企业社会责任 |
水合物 | 没有任何 | 进步,部分 | 部分可恢复 | 任何 | 无(CSR) |
示例框架 | 11岁 | 阿斯特罗,长老 | Marko,Qwik,氢能 | 接下来,Remix | 创建 React 应用 |
我尽量避免使用首字母缩略词,但用表格来表达更简洁。如果你遇到不熟悉的词语,可以参考文末的词汇表。
所有这些框架在多种场景下都能完美运行,但只挑选了几个适合的选项。
这只是一小部分示例。显而易见,选择有很多。说实话,我们的分类只能在一定程度上表明您所选择的不同工具的特点。但即便如此,这或许可以作为基于实际需求的对话起点,帮助您找到适合您项目的解决方案。
路由——Web 的骨干
网络建立在将位置描述为路径的理念之上。URL 是整个网络运作背后的驱动力。
近年来,我们在处理路由方面变得更加自由,但处理方式才是决定我们网站和应用程序行为的最根本因素。整个架构和范式都围绕着如何处理路由而产生,因为它是其他一切构建的基础。所以,这就是我们着手研究的原因。
您如何导航?
服务器 | HTML 交换 | 杂交种 | 客户 | |
---|---|---|---|---|
代码条目 | 多种的 | 多种的 | 单身的 | 单身的 |
整个页面重新加载 | 是的 | 不 | 不 | 不 |
保持客户端状态不变 | 不 | 不 | 是的 | 是的 |
客户端转换 | 不 | 是的 | 是的 | 是的 |
在服务器上渲染(第一次渲染后) | 是的 | 是的 | 是的 | 不 |
浏览器中的 JavaScript | 没有任何 | 低的 | 中等的 | 高的 |
例子 | 表达 | TurboLinks | React 服务器组件 | React 路由器 |
多页应用(服务器路由)与单页应用(客户端路由)通常是我们首先要区分的。这和网站与 Web 应用的区分一样古老。但细微差别在于,所有网站都首先由服务器提供服务。只需删除服务器渲染的 SPA<script>
标签,它就变成了多页应用 (MPA)。
当我们审视中心化的新方法时,我们发现这种区分越来越难以区分。需要注意的关键是,这些混合方法都是为了在保持客户端导航无需重新加载的同时,更好地利用服务器。它们最大的不同之处在于,它们能够将客户端状态保持在变化以下。
如果说关于路由有什么值得铭记的,那就是每当我们在这方面取得重大进展时,我们构建应用的整个范式都会发生变化。从最初的服务器路由到客户端路由,见证了 SPA 的诞生。推送状态和历史记录 API 促成了我们今天看到的同构 SSR SPA。而今天,我们正处于另一场转变的边缘。
资源:
介绍适用于 Rails 4.0 的 TurboLinks - Fabian Becker,2012
单页应用是否毁了 Web? - Rich Harris,2021 年 10 月
服务器端路由的回归- Ryan Carniato,2022 年 1 月
重新混合 React Router - Ryan Florence,2022 年 3 月
路由 我不够聪明,无法使用 SPA - Taylor Hunt,2022 年 4 月
渲染——将 HTML 呈现在视图中
对于渲染,无论使用哪种技术,最终结果都是一样的。为了让你的网站用户能够看到内容,它会被渲染成浏览器可以解释和显示的 HTML。
所以整个问题归结为“何时”。这其中有很多第三级考虑因素,例如数据可用性和缓存能力。由于基础设施限制或缓存效率低下导致的高延迟数据可能会显著改变性能特征,但我们仍然可以通过这种分类建立有意义的关联。
什么时候渲染?
静态(或缓存) | SSR(流媒体) | SSR(异步) | SSR(壳牌) | 客户 | |
---|---|---|---|---|---|
何时渲染? | 提前 | 服务器 | 获取数据后的服务器 | 服务器和浏览器 | 浏览器 |
何时获取数据? | 提前 | 服务器请求 | 服务器请求 | 在浏览器中 | 在浏览器中 |
TTFB | 低的 | 低的 | 高的 | 低的 | 低的 |
FCP | 低的 | 低的 | 中等的 | 低的 | 中等的 |
液晶聚合物 | 低的 | 中等的 | 中等的 | 高的 | 高的 |
液晶显示面板:液晶显示面板 | LCP=FCP | LCP > FCP | LCP=FCP | LCP > FCP | LCP > FCP |
为客户互动提供水分 | 是的 | 是的 | 是的 | 是的 | 不 |
示例 | FTP 服务器中的 HTML,11ty | Marko,React 18,Solid | 接下来,Nuxt,SvelteKit | 应用外壳,Jamstack | 创建 React 应用 |
渲染的很大一部分都与数据可用性有关,数据获取的时间对渲染的时间有很大的影响。通常的做法是将工作拆分,在服务器上渲染静态部分,然后在浏览器中获取数据后渲染其余部分。
同样重要的是,由于所有网站都始于服务器,任何服务器渲染的网站如果足够静态,也可以缓存,从而获得这些优势。在某些时候,你会承受影响,而这很大程度上取决于不同节点对延迟的容忍度。
按需缓存和在重新验证时过期的缓存策略有很多术语,例如增量静态重新生成 (ISR)、DPR,因为这些功能目前大多是特定于平台的。随着我们探索边缘渲染,期待看到更多有趣的缓存策略出现。
我们的计算距离最终用户如此之近,但这并不一定能改变数据延迟的问题。流式传输通过尽快将内容呈现在用户面前,部分缓解了这个问题,但我们期待更积极的缓存策略,因为我们将继续努力兼顾两者。
资源:
异步片段:使用 Marko 重新发现渐进式 HTML 渲染- Patrick Steele-Idem,2014 年 12 月
新的前端堆栈:JavaScript、API、标记- Mathias Biilmann,2016 年 4 月
Next 9.4:增量静态再生 Beta 版- Tim Neutkens,2020 年 5 月
JavaScript 中的服务器渲染:优化性能- Ryan Carniato,2021 年 2 月
分布式持久渲染:一种用于更快构建的全新 Jamstack 方法- Mathias Biilmann,2021 年 4 月
Hydration——JavaScript 框架的最大挑战
Hydration 是在浏览器中完成的工作,使服务器渲染的应用程序/页面处于与客户端渲染相同的状态- Michael Rawlings
事实证明,高效地进行水合是一项挑战。它至关重要,因为缓慢的水合会给人一种网站完全交互的错觉,而实际上并非如此。我们讨论诸如“可交互时间”之类的指标,并关注页面加载指标。但不同的技术往往会推迟工作,而不是解决问题,而衡量这些指标的工作仍在进行中。
谈论“水合”并不容易,这于事无补。我们经常谈论解决方案的质量,而不是方法的名称。原因是“水合”的运作涉及三个维度:
什么时候加载?
急切(加载) | 渐进式(空闲) | 渐进式(可见) | 渐进式(互动) | |
---|---|---|---|---|
负载时 | 页面加载时 | 空闲回调 | 路口观察员 | 事件 |
优先事项 | 高的 | 中等的 | 低的 | 低的 |
需要 | 立即可见并保湿 | 可见的非关键 | 屏幕外,昂贵 | 非关键,昂贵 |
影响 | 互动时间 | 加载完成 | 滚动延迟 | 输入延迟 |
您捆绑/序列化什么?
没有任何 | 部分的 | 满的 | |
---|---|---|---|
什么是捆绑 | 没有什么 | 互动岛屿 | 全部 |
什么是序列化 | 没有什么 | 无 - 最小 | 全部 |
只知道服务器代码 | 是的 | 是的 | 不 |
路由 | 非客户 | 非客户 | 任何 |
加载时执行什么?
可重玩 | 可恢复 | |
---|---|---|
执行组件 | 是的 | 不 |
恢复状态 | 是的 | 不 |
运行客户端效果 | 是的 | 是的 |
附加事件处理程序 | 是的 | 是的 |
执行成本 | 高的 | 低的 |
序列化成本 | 低的 | 高的 |
更具挑战性的是,只有将它们组合在一起,我们才能推断出它们对交互时间 (TTI) 或首次输入延迟 (FID) 的影响。可恢复性的执行成本较低,但序列化成本较高,但这可以通过部分恢复来抵消。同样,当执行成本较高时,渐进式恢复的成本也会更高。
如今,大多数 JavaScript 框架都具备 Eager、Full 和 Replayable 的特性。这包括所有 SPA 框架以及构建于其之上用于创建 SPA 的元框架。要找到降低这种不断增长的成本的方法,需要大量的创造力和新的探索。与其他所有事物一样,我们看到了向服务器端的回归,但不会回到过去。
资源:
也许你不需要那个 Spa - Michael Rawlings,2020 年 5 月
岛屿架构- Jason Miller,2020 年 8 月
引入零捆绑大小的 React 服务器组件- Dan Abramov & co,2020 年 12 月
你的未来会使用 JavaScript 吗? - Ryan Carniato,2021 年 5 月
什么是部分水合,为什么每个人都在谈论它? - Anthony Campolo,2021 年 11 月
为什么 JavaScript 框架中的高效水合如此具有挑战性- Ryan Carniato,2022 年 2 月
征服 JavaScript 水合- Ryan Carniato,2022 年 3 月
水合是纯粹的开销- Misko Hevery,2022 年 4 月
结论
嗯,这更像是个开始。分类只能作为指导方针,而不是规则。如果说2022年迄今为止有什么表现的话,那就是正在进行大量的创新。
久经考验的解决方案正在扩展其产品范围。静态生成器提供按需服务器渲染。流式渲染正在成为主流渲染技术。
新的解决方案正在攻克所有新领域,尤其是在数据融合领域。随着我们学习如何更好地让服务器参与进来,路由很可能成为今年剩余时间的焦点。
这意味着我们拥有了更多选择。但这并不是坏事。一点也不坏。
特别感谢 Dan Jutan 和 Michael Rawlings 的审阅,以及 Addy Osmani 的最初启发并引导我回到 Jason 的应用全息图。
词汇表
姓名 | 描述 | |
---|---|---|
温泉 | 单页应用程序 | 客户端路由的单代码输入应用程序体验 |
公共管理硕士 | 多页应用程序 | 服务器路由的多代码入口站点体验 |
苏维埃社会主义共和国 | 服务器端渲染 | 按需在服务器上渲染 HTML |
萨格 | 静态站点生成 | 提前渲染 HTML |
情报、监视与侦察 | 增量静态再生 | 从缓存中提供服务,同时根据需要在后台重新渲染 |
达伊沙 | 分布式持久渲染 | 首次请求时缓存资源,并从缓存中提供服务,直到失效 |
TTFB | 第一个字节的时间 | 从发送请求到浏览器收到响应的第一个字节的时间 |
FP | 第一次油漆 | 距离第一次浏览器绘制事件的时间 |
FCP | 首次内容绘制 | 浏览器第一次绘制事件显示有意义的内容的时间 |
液晶聚合物 | 最大的内容绘画 | 大部分可见内容绘制完成的时间 |
电信技术 | 互动时间 | 所有阻塞资源和 JavaScript 执行完毕的时间 |
火焰离子化检测器 | 首次输入延迟 | 从第一次交互触发到结果处理的时间 |