捍卫现代网络

2025-05-26

捍卫现代网络

我预计这篇文章会惹恼所有人:反 JavaScript 斗士,他们对我们在现代网站上大量使用的内容感到震惊;有人认为 Web 平台对于交互式应用程序来说已经支离破碎我们应该重新开始;React 用户;那些使用手工 JS 和 HTML 的老派;以及Tom MacWright,自从多年前我第一次注意到他在 Mapbox 上的工作以来,我一直对他敬佩不已。但我想,这就是发表意见的代价。

Tom 最近发表了一篇名为《反思现代网络》的文章,在前端领域引起了轩然大波。你应该读一读这篇文章,或者至少看看CliffsNotes。文中有很多观点我在不同程度上表示赞同:

React 有一个最佳点:在适度交互的界面中...但是在这个最佳点的两边还有很多东西。

对于一个高度静态的网站,在客户端运行 React 绝对是大材小用。同样,如果你的应用交互性很强,也应该避免使用 React——众所周知,如果你想要 60fps 的动画,你很可能不得不绕过 React 的更新周期,转而采用更命令式的方式(事实上,像react-spring这样的库就是这样做的)。虽然 React 确实如此,但对于一般的组件框架来说,情况并非如此。

用户会话长得惊人:有人可能会连续几周在一个标签页中打开你的网站。我见过这种情况。如果他们打开“关于页面”,并保持该标签页打开一周,然后请求“主页”,那么他们请求的主页将由他们上周下载的索引包决定。这是一个非常奇怪且很少被讨论的情况。

这是一个很好的观点,但实际上并没有得到解决,尽管(正如汤姆承认的)这实际上只是加剧了一个一直存在的问题。我认为有解决方案——我们可以迭代“索引包”的方法,我们可以将网站版本包含在cookie中,并在出现不匹配时显示可操作的反馈——但我们确实需要花时间来解决这个问题。

这是你的初创公司的主页,上面有一个“注册”按钮,但在 JavaScript 加载完成之前,这个按钮不会有任何作用。所以你需要一些补偿。

这确实很烦人,尽管做这种事很容易——我们只需要足够关心:

<button class="sign-up" disabled={!is_browser}>
  {is_browser ? 'Sign up' : 'Loading'}
</button>
Enter fullscreen mode Exit fullscreen mode

但我不确定这与 React 风格的框架有什么关系——无论你的前端采用什么形式,这个问题都存在,除非你让它在没有 JS 的情况下工作(你应该这样做!)。

您以前的轻量级应用程序服务器现在要做相当多的工作,运行 React 并发出 API 请求以进行预渲染。

再次强调,这的确没错,但更多是 React 独有的。React 的服务器端渲染方法——构建组件树,然后将其序列化——会带来一些框架所不具备的开销,例如,框架会将你的组件(你好!)编译成函数,这些函数只需连接字符串即可实现服务器端渲染,而服务器端渲染的速度会显著提升。而且这些 API 请求无论如何都得发起,所以尽早发起这些请求是明智之举,尤其是在你的应用服务器和 API 服务器距离较近(甚至是同一个服务器)的情况下。

API 的梦想是,你拥有通用、灵活的端点,可以在其上构建任何 Web 应用程序。但这个想法很快就破灭了。

阿门。只需将整个“API”部分阅读几遍即可。


撇开这些小问题不谈,Tom 确实指出了当前 Web 开发领域存在的一些实际问题。但我认为这篇文章得出了一个危险的结论。

让我们首先剖析一下这句话:

例如,我可以保证这个博客比任何 Gatsby 博客都快(并且非常喜爱 Gatsby 团队),因为 React 静态站点无法做任何事情使其比非 React 静态站点更快。

恕我直言,我不认为 Gatsby 是一个特别合适的基准测试。gatsby new my-site在生产模式下,入门应用执行压缩后的 JavaScript 代码,生成一个完全静态的页面,大小只有 266kB;而gatsbyjs.org的页面大小则为 808kB。说实话,这些数字并不令人印象深刻。

gatsbyjs.org 的 Lighthouse 性能评分

Gatsby 主页的Lighthouse 分数 ,通过webpagetest.org/easy获得。

撇开这一点不谈,我不同意这个前提。当我点击 Tom 的无 JS 网站上的链接时,浏览器首先会等待确认是点击而不是刷/滑动,然后发出请求,之后我们必须等待响应。使用框架编写的网站并进行客户端路由,我们可以开始做更多有趣的事情。我们可以根据分析结果,对用户可能与哪些内容进行合理的猜测,并为他们预加载逻辑和数据。我们可以在用户第一次触摸(或悬停)链接时立即发起请求,而不是等待点击确认——最坏的情况是,我们已经加载了一些内容,如果用户真的点击了链接,这些内容稍后会派上用场。我们可以提供更好的视觉反馈,表明加载正在进行,并且即将发生转换。而且我们不需要加载整个页面的内容——通常,我们只需要少量 JSON 代码就可以了,因为我们已经拥有了页面的 JavaScript。手动完成这些工作极其困难。

除此之外,原生静态网站的目标还不够远大。就拿过渡效果来说吧。Web 开发者目前还深陷于页面分离、过渡效果不协调的思维模式——点击一个链接,整个页面都会被替换,无论是通过客户端路由还是页面重新加载——而原生应用开发者则在另一个层面上思考:

要让网络达到这一目标,不仅需要技术进步,还需要文化的转变。但如果我们放弃现有的发展轨迹,就肯定无法实现这一目标。而这正是汤姆暗示的。


我还没听说过有哪个平台要求你用一套与后续交互逻辑不同的技术来编写初始渲染逻辑。这个想法听起来很傻。但在 Web 领域,由于其独特的历史,多年来这一直是常态——我们会用 PHP、Rails 或其他语言生成一些 HTML,然后在上面“添加一些 jQuery”。

随着 Node 的出现,情况发生了改变。我们能够使用 Web 原生语言进行服务器端渲染、与数据库通信等等,这真是一个了不起的进步。

这种模型存在一些问题。Tom 指出了其中的一些。他没有讨论的另一个主要问题是,服务器渲染的 SPA 模型通常会以一种需要复制大量数据的方式“水化”整个初始页面——一次在 HTML 中,一次在 JSON blob 中(后者会传递给客户端版本以产生完全相同的结果)——并且可能会在用户开始与应用交互期间阻塞主线程。

但我们可以解决这些问题。接下来,我们正在围绕(例如)在单​​个应用中混合静态和动态页面进行令人惊叹的创新,这样您就可以享受纯静态模型的优势,而不会最终受到其限制。Marko实现了智能组件级数据融合,我希望其他框架也能效仿。Svelte配套框架Sapper有一个明确的目标,即最终除了(微型)路由器本身之外,不再向不需要它的页面发送任何 JS。

我所期望的未来——我所预见的未来——是拥有可供最多人(包括设计师)使用的工具,能够根据需要在服务器和客户端之间智能地移动工作,让我们能够构建与原生用户体验相媲美的体验(是的,甚至博客也不例外!),并且将网站的一部分升级为“交互式”或从“静态”升级为“动态”,无需使用不同技术的不同团队进行沟通。我们只有致力于 Tom 所批评的范式——类似 JavaScript 的组件框架服务器渲染 SPA,才能实现这一目标。(欢迎使用更好的名称。)

现代网络存在缺陷,我们应该讨论。但我们不应该放弃它。

文章来源:https://dev.to/richharris/in-defense-of-the-modern-web-2nia
PREV
保持警惕
NEXT
制作响应式、无 JavaScript 图表的新技术