【前端开发】Remix与Next.js

很容易,我们被问到的最大问题是:

Remix与Next.js有何不同?

看来我们必须回答这个问题!我们想直接而不带戏剧性地解决这个问题。如果你是Remix的粉丝,并且想开始在推特上对这篇文章做出沾沾自喜的反应,我们恳请你在点击推特按钮之前不要沾沾自自喜🤗. 涨潮使所有的船都浮起来。早在Vercel成立之前,我们就和Vercel的人是朋友。他们做得很好,我们尊重他们所做的工作!

但毫无疑问,我们认为Remix比Next.js有更好的折衷方案。(否则我们就不会构建它…)

我们鼓励您阅读整篇文章。在这段对话中,有很多细微之处没有在闪亮的图表和动画中捕捉到。最后,希望你能考虑在下一个项目中使用Remix(并非双关语😂).

tl;dr

  • Remix在提供静态内容方面与Next.js一样快或更快
  • Remix在提供动态内容方面比Next.js更快
  • Remix即使在慢速网络上也能提供快速的用户体验
  • Remix可以自动处理错误、中断和比赛情况,Next.js则不会
  • Next.js鼓励客户端JavaScript提供动态内容,Remix没有
  • Next.js需要客户端JavaScript进行数据突变,Remix不需要
  • Next.js构建时间随着数据线性增加,Remix构建时间几乎是即时的,并且与数据解耦
  • Next.js要求您更改应用程序架构,并在数据扩展时牺牲性能
  • 我们认为Remix的抽象会带来更好的应用程序代码

背景

我们认为比较这些框架的最公平的方法是以Vercel团队自己编写的Next.js应用程序为例。既然他们写了,他们所做的决定应该反映出他们打算如何构建你的应用程序。它还应该展示Vercel团队最引以为豪的功能。

我们从Next.js示例页面移植了Commerce示例。它有一些我们喜欢的现实世界功能,似乎是他们投入最多精力的功能。

  • 初始页面加载对电子商务至关重要
  • 搜索页面上的动态数据
  • 购物车的数据突变
  • 能够与多个提供者集成,说明框架如何帮助您抽象

我们实际上构建了两个版本:

  • 最小端口-我们只是复制/粘贴/调整Next.js代码,使其在Remix上运行,而不是在Next.js.这与Next.jsDemo一样部署到Vercel。这是一个很好的框架比较,因为除了框架之外的所有东西都是一样的。
  • 重写-这两个框架实际上没有太多API重叠,Remix可以在不同于Next.js的基础设施上运行。为了真正实践Remix的设计,我们将示例重写为惯用的Remix,甚至在应用程序中建立了一个快速的图像优化路线,使其成为100%的Remix。

请注意,这个应用程序并不能锻炼我们认为Remix很酷的一切(比如嵌套路线!)。一旦我们回答了这个问题,我们就可以继续谈论remix了,所以请继续关注!

此外,我们在发布之前与Vercel分享了这篇文章。事实证明,他们的例子是在旧版本的Next.js上运行的,他们对其进行了更新,所以我们花时间对其进行返工,以与他们的最新例子进行比较。

说真的,我们喜欢Vercel

我们认为他们是朋友,甚至是合作伙伴,因为Vercel是Remix的优秀部署目标。我已经将Remix应用程序部署到了几乎所有我听说过的托管服务中。Vercel的开发经验无疑是我的最爱。“开发、预览、发货”的咒语具有实际效果。就在今天早上,@gt_codes和我正试图找出一个生产错误,让每个预览部署都有一个小屏幕截图,可以帮助我们在几秒钟内找到错误的提交。这是好东西。

现在这是一种有趣的关系,因为我们不仅仅是朋友和技术合作伙伴,我们还是框架竞争对手!因此,对于我们的朋友、合作伙伴和竞争对手Vercel,Lee精彩地阐述了这篇文章背后的动机:

当DevTools存在竞争时,开发人员会胜出:

  • ◆ Svelte正在推动React
  • ◆ Remix正在推Next.js
  • ◆ Prisma正在推动ORM
  • ◆ Deno正在推Node.js
  • ◆ Supadase正在推动Firebase
  • ◆ esbuild/SWC正在推动JS工具
  • ◆ Bun正在推动SWC
  • 还有什么?
  • --Lee Robinson(@leeerob)2021年11月30日

请在阅读这篇文章的背景下阅读。让我们加油!

自我描述

我想你可以通过建造它的人对它的描述来了解很多。(如果你在推特上关注我,你就会知道我一直在努力迭代我们的!)

Next.js将自己描述为:

React生产框架。Next.js为您提供了最佳的开发体验,提供了生产所需的所有功能:混合静态和服务器渲染、TypeScript支持、智能绑定、路由预取等。不需要配置。

Next.js由Vercel构建。看看Vercel平台的GitHub回购,它指出:

Vercel是一个用于静态网站和前端框架的平台,旨在与您的无头内容、商业或数据库集成。

我们将Remix描述为:

Remix是一个边缘原生、全栈JavaScript框架,用于构建现代、快速和有弹性的用户体验。它将客户端和服务器与web标准统一起来,这样您就可以少考虑代码,多考虑产品。

我们将留给您来对比这些描述。

主页,视觉完整

remix和Next.js一样快吗?

这通常是人们问的第一个问题。Next.js经常使用“默认情况下的性能”这句话,他们已经做到了!让我们看看每个应用程序渲染“视觉完整”页面的速度有多快。

我们通过WebPageTest运行这些网站。这是一个很好的工具,可以在这篇文章中生成比较gif。在每次比较中,我们对每个框架进行了五次测试,并从中选出最好的一次。

每个比较的上方都有一个标题,链接到生成动画的结果。您只需点击WebPageTest.com上的“重新运行测试”即可自由验证所有内容。

第一台是从弗吉尼亚州通过有线调制解调器连接到互联网运行的。


主页,弗吉尼亚州,凯布尔

wpt-virginia-homepage-cable

在我们说什么之前,让我们承认这三个版本都很快,甚至不值得比较谁更快。这对Next.js也有点不公平,因为cookie横幅的小动画被认为是“视觉上完整的”,而Remix网站没有它。让我们用慢镜头来看它:


主页,弗吉尼亚州,Cable,Slow Mo

wpt-virginia-homepage-cable-slow

现在我们可以看到Next.js实际上完成了0.8s。同样,它们都很快。我还用3G网络连接对它们进行了同样的测试,结果是一样的:速度都很快,看起来都差不多。

✅ Remix和Next.js一样快

为什么应用程序很快

为什么Next.js很快:主页使用带有getStaticProps的静态站点生成(SSG)。在构建时,Next.js从Shopify中提取数据,将页面呈现为HTML文件,并将其放在公共目录中。当部署站点时,静态文件现在在边缘(Vercel的CDN之外)提供服务,而不是在单个位置访问原始服务器。当收到请求时,CDN只是为文件提供服务。数据加载和渲染已经提前完成,因此访问者不需要支付下载+渲染的费用。此外,CDN在全球范围内分布,靠近用户(这是“边缘”),因此对静态生成的文档的请求不必一直传递到单个源服务器。

为什么Remix端口很快:Remix不支持SSG,所以我们在重新验证缓存指令时使用了HTTP过时指令(SWR,不能与Vercel的SWR客户端获取包融合)。最终的结果是一样的:边缘的静态文档(即使在相同的CDN上,Vercel的)。不同的是文件是如何到达那里的。

不是在构建/部署时获取所有数据并将页面呈现为静态文档,而是在获取流量时启动缓存。文档从缓存中提供,并在后台为下一个访问者重新验证。与SSG一样,当你获得流量时,没有访问者支付下载+渲染成本。如果您想知道缓存未命中,我们稍后会讨论。

SWR是SSG的一个很好的替代方案。部署到Vercel的另一个好处是他们的CDN支持它。

你可能想知道为什么Remix端口没有Next.js那么快。由于Remix还没有内置图像优化功能,我们只是将图像指向Next.jss应用程序🤫. 浏览器必须打开与两个域的连接,这会将图像加载延迟0.3秒(您可以在网络瀑布上验证这一点)。如果这些图像是自托管的,那么它就在那里,其他两个大约在0.7秒。

为什么Remix重写很快:这个版本不是用SSG或SWR在边缘缓存文档,而是用Redis在边缘缓存数据。事实上,它实际上也使用Fly.io在边缘运行应用程序。最后,它有一个快速的图像优化资源路由,可以写入持久卷。它基本上是自己的CDN😎.

这在几年前可能很难构建,但在过去几年中,服务器环境发生了重大变化,而且只会变得更好。

加载动态页面

Remix与Next.js有何不同?

这是我们的下一个问题。功能集有很多不同,但一个主要的架构差异是Remix不依赖SSG来提高速度。

在几乎每一个应用程序中,你最终都会遇到SSG无法支持的情况。对于我们在这里比较的应用程序,它是搜索页面。

限制条件是用户可以提交无限数量的查询。由于宇宙当前对空间和时间的限制,您无法静态生成无限页面。SSG不在谈判桌上。

Search Page, Cached, Virginia, Cable

wpt-virginia-search-cable.gif

由于SSG不能扩展到动态页面,Next.js切换到从用户浏览器获取客户端数据。在网络瀑布上达到峰值会告诉我们为什么它比Remix慢2.3倍。

wpt-search-remix-waterfall.png

在Next.js应用程序开始加载图像之前,Remix应用程序就已经完全完成了。也许在web性能方面最重要的事情是并行化网络瀑布。在Remix,我们对此非常狂热。

为什么Next.js较慢:Next.js引入了我们所说的“网络瀑布请求链”。因为这里不能使用SSG,所以该应用程序从用户的浏览器中获取搜索结果。在获取数据之前,它无法加载图像,在加载、解析和评估JavaScript之前,它也无法获取数据。

在客户端获取还意味着在网络上有更多的JavaScript,以及更多的解析/评估时间。有时我们忘记了parse/eval,但您可以看到JS在第15个请求上的执行时间比文档下载的时间长!Next.js发送的JavaScript比Remix多1.5倍,566 kB,而未封装371 kB。在网络上,它被压缩了50 kB(172 kB对120 kB)。

在浏览器中做更多的工作开始增加。查看底部显示CPU利用率和浏览器主线程活动的行。Next.js应用程序正忙于一个红色的“长任务”,以减慢速度。

为什么Remix仍然像主页一样快:Remix的例子实际上都没有在请求中与Shopify API交谈。虽然SSG无法缓存搜索页面,但Remix版本可以:使用SWR或Redis。当您有一种单一的动态生成页面的方法时,您可以在不更改应用程序代码的情况下调整缓存策略。结果是在通常访问的页面上的SSG速度。“/search”页面以及左侧导航上的类别和常见查询(如“tshirt”)可能会启动。

动态页面缓存未命中

是的,但是缓存未命中怎么办?

在这件事上,你可能不会相信我,我也无法证明我们的缓存是空的,但这是Remix中的一个缓存错误(我发誓要死,把针扎进我的眼睛)。


搜索页面,空缓存,弗吉尼亚州,有线电视

wpt-virginia-search-miss-cable.gif

事实上,我撒谎了。这是remix重写的缓存命中率。缓存未命中速度更快(0.6秒🤭). 我真的没想到你会相信我,所以我在图中放了较慢的缓存命中率😅

不可能的

结果发现Shopify API相当快。

由于Next.js应用程序直接从浏览器获取到Shopify API,我们可以查看测试的网络图,发现请求只花了224ms。浏览器与API建立连接的时间比发出请求的时间长!(他们可以在最初的HTML中使用<link rel=“preconnect”/>来加快速度。)

如果用户的浏览器能够如此迅速地向Shopify发出请求,那么Remix服务器肯定可以更快地完成。用户到云的连接总是比服务器慢,最好是保持数据获取。

底线是,当使用Shopify API时,缓存几乎是毫无意义的。缓存命中或未命中将几乎无法区分。

这可以通过减慢用户的网络速度并查看发生了什么来最好地说明。让我们再做一次缓存丢失,这次是从香港通过3G连接。


搜索页面,空缓存,香港,3G

wpt-hkg-search-3G.gif

Next.js现在落后3.5秒,即使是缓存未命中。怎么了?

你说Shopify API很快!

Next.js在加载数据之前不能加载图像,在加载JavaScript之前不能加载数据,在加载文档之前不能加载JavaScript。用户的网络是该链中每一步的乘数😫.

在Remix中,唯一的环节是等待文档能够加载图像。总是在服务器上获取的Remix设计消除了用户的网络在其他地方的乘数。

收到请求后,Remix可以立即开始从Shopify获取。它不必等待浏览器下载文档,然后再下载JavaScript。无论用户的网络速度有多慢,服务器上Shopify API的获取不会改变,可能低于200ms。

架构差异

当Next.js转向客户端抓取时,用户体验并不是唯一受到影响的东西。该应用程序现在有两组不同的抽象用于与Shopify对话:一组用于SSG,另一组用于浏览器。

像这样的架构分歧带来了一些主要问题:

  • 你必须在浏览器中进行身份验证吗?
  • API是否支持CORS?
  • API SDK甚至可以在浏览器中工作吗?
  • 我们如何在构建代码和浏览器代码之间共享代码?
  • 在浏览器中公开API令牌可以吗?
  • 我们刚刚发给每位访客的代币有什么权限?
  • 这个函数可以使用process.env吗?
  • 这个函数能读取window.location.origin吗?
  • 如何发出在两个地方都有效的网络请求?
  • 我们可以将这些响应缓存在某个地方吗?
  • 我们应该制作一个在两个地方都能工作的同构缓存对象,并将其传递给不同的数据获取函数吗?

(我说的是同构的)(这与这个帖子正交)(gah PROFUNCTOR OPTICS!)

让我们为Remix回答以下问题,您只需在服务器上抽象Shopify API:

  • 你必须在浏览器中进行身份验证吗?(否)
  • API是否支持CORS?(没关系)
  • API SDK甚至可以在浏览器中工作吗?(不需要)
  • 我们如何在构建代码和浏览器代码之间共享代码?(你不必)
  • 在浏览器中公开API令牌可以吗?(不需要)
  • 我们刚刚发给每位访客的代币有什么权限?(你没有!)
  • 这个函数可以使用process.env吗?(是)
  • 这个函数能读取window.location.origin吗?(否)
  • 如何发出在两个地方都有效的网络请求?(无论您想要什么,它都不在浏览器中)
  • 我们可以将这些响应缓存在某个地方吗?(当然,HTTP、redis、lru缓存、持久卷、sqlite…)
  • 我们应该制作一个在两个地方都能工作的同构缓存对象,并将其传递给不同的数据获取函数吗?(不需要!)

这些问题回答得越简单,抽象就越好,从而产生更简单的代码。

如果Next.js应用程序不再使用客户端获取,而是使用getServerSideProps,他们可能会缩小差距,并对这些问题有更简单的答案。值得注意的是,Next.js文档经常会将您从服务器获取推到SSG或客户端获取,不过:

如果不需要预渲染数据,那么应该考虑在客户端获取数据。

它们还鼓励客户端获取包含用户数据的页面,从而再次将您推向更大的体系结构差异。

例如,[客户端获取]适用于用户面板页面。因为仪表板是一个私人的、特定于用户的页面,所以SEO并不相关

正如我们在这里看到的,服务器渲染也是为了更好的性能,而不仅仅是SEO。

这里的根本区别在于Next.js有四种在页面上获取数据的“模式”:

  • getInitialProps-调用服务器端和客户端
  • getServerSideProps-称为服务器端
  • getStaticProps-在构建时调用
  • 客户端获取-在浏览器中调用

remix只有一个:loader。只在一个地方运行的一件事比在三个地方运行四件事更容易抽象。

架构分歧的代价

让我们试着量化这种架构差异的成本。也许这个应用程序最困难的开发任务是抽象商务后端。该应用程序的设计方式可以将任何东西插入其中:Shopify、BigCommerce、Spree、Saleor等。

在Next.js应用程序中,Shopify集成位于此文件夹中。今天在上面运行cloc会产生:

     101 text files.
      93 unique files.
       8 files ignored.

github.com/AlDanial/cloc v 1.92
---------------------------------------------------------------------
Language           files          blank        comment           code
---------------------------------------------------------------------
TypeScript            88            616           2256           5328
GraphQL                1           1610           5834           2258
Markdown               1             40              0             95
JSON                   2              0              0             39
JavaScript             1              1              0              7
---------------------------------------------------------------------
SUM:                  93           2267           8090           7727
---------------------------------------------------------------------

近100个文件中的近8000行代码。我为其他集成运行了它,情况也是如此。它们都接近100个文件,并在10000行代码上徘徊。几乎所有的代码都能进入浏览器。

以下是与Shopify的remix集成。

  • 1个文件
  • 608行代码
  • 这些都没有进入浏览器

这就是架构差异的代价。Next.js抽象必须预测并参与构建和浏览器。Remix抽象仅在服务器上。

你可能想知道这两家Shopify提供商是否有相同的功能集,也许我们是在欺骗。其中许多代码用于身份验证和愿望清单,但Shopify提供商没有使用任何一个(但必须为它们导出模块)。使用这两个网站,它们似乎具有相同的功能集。无论如何,如果我们确实错过了什么,很难想象当应用程序中的可见功能只占其中的十分之一时,需要7000行代码才能到达那里。

即使Next.js移到了搜索页面的getServerSideProps,他们仍然需要几乎所有的代码来实现数据突变功能,但我现在已经超越了自己!

边缘本机

我们经常谈论“部署到边缘”。这是什么意思?以下是另一个来自香港的缓存未命中,这一次使用快速用户网络:


搜索页面,空缓存,香港,有线

wpt-hkg-search-miss-cable.gif

这一次我们将讨论两个Remix应用程序之间的区别。我们已经知道Next.js版本由于网络瀑布链的原因速度较慢。

两个Remix应用程序都在服务器上获取,那么为什么Remix端口远远落后于Remix Rewrite呢?

答案很简单:Remix端口在Vercel函数中运行,而Vercel的函数不会在边缘运行您的代码,它们在一个地区运行,默认为华盛顿特区。那离香港很远!

这意味着用户必须从香港一路到达华盛顿特区,然后服务器才能开始从Shopify获取数据。当服务器完成后,它必须将文档一直发送回。

Remix Rewrite也在华盛顿特区运行,但它也在香港运行!这意味着用户可以非常快速地跳转到Remix服务器,在那里一切都会更快。

这就像骑自行车去火车进城,而不是全程骑自行车。

🚲-----------------------------------------🏢

🚲-----🚊====🏢

你可以在网络瀑布中看到这一幕(和往常一样):

wpt-hkg-search-rewrite-waterfall.png

基础结构的差异体现在文档的第一个蓝色条中。在remix港,它要大得多。这是用户在Vercel功能自行车道上骑自行车环游半个世界。在Remix Rewrite中,它上了火车,进入了Shopify API,并很快返回。

这个版本运行在Fly.io上,可以在全球数十个地区运行Node.js服务器。remix并不依赖Node.js。它可以在任何JavaScript环境中运行。事实上,它已经在Cloudflare Workers中运行,这意味着你正在他们分布在世界各地的250台服务器上运行代码。离用户再近不过了!

这就是为什么我们说Remix是“边缘原生”。Next.js依赖于Node.js,因此目前部署边缘的能力有限。

为了让开发者体验更好,我们在这方面还有很多工作要做。我们现在只正式支持Node.js和Cloudflare,但我们正在积极开发Deno,社区成员在Fastly上运行了Remix。

当你使用像Remix这样的“边缘原生”框架时,你不再需要决定哪些用户可以获得更快的体验。您可以为每个用户提供快速体验,无论他们身在世界何处。

边缘就是Remix的初衷。正如你所看到的,这是非常有希望的。据我们所知,Vercel团队也在努力将您的应用程序部署到边缘。remix已经准备好了,我们迫不及待地想试试。

客户端转换

这两个框架都支持链接预取的即时转换,但Next.js只对从SSG创建的页面执行此操作。搜索页面再次关闭。(也许下次,体育)

然而,Remix可以预取任何页面,因为在数据加载方面没有架构差异。预取未知的、用户驱动的搜索页面URL与预取已知的产品URL没有什么不同。

事实上,Remix预取不仅仅限于链接,它可以在任何时间、任何原因预取任何页面!请检查此项,在用户键入时预取搜索页面:

搜索输入预取,快速3G

0:00

/ 0:07

没有微调器,没有骨架,即时用户体验,即使在慢速网络上也是如此🏎

这也非常容易做到。

import { Form, PrefetchPageLinks } from "@remix-run/react";function Search() {let [query, setQuery] = useState("");return (<Form><input type="text" name="q" onChange={(e) => setQuery(e.target.value)} />{query && <PrefetchPageLinks page={`/search?q=${query}`} />}</Form>);
}

由于Remix使用HTML的<link rel=“prefetch”>(而不是像Next.js这样的内存缓存),浏览器实际上是发出请求的,而不是Remix。观看视频,您可以看到当用户中断当前获取时,请求是如何被取消的。Remix不需要发送一个字符的代码就可以实现一流的异步处理#使用平台。。。或者,呃,#reuseThePlatform😎?!

数据突变

这就是Remix和Next.js看起来完全不同的地方。你的应用程序代码有一半与数据突变有关。是时候让你的网络框架尊重这一点了。

突变是如何在Next.js中工作的:Next.js在这里对你没有任何帮助<按钮单击={itsAllUpToYou}>。通常,您将管理表单的状态以了解发布内容,添加要发布到的API路由,自己跟踪加载和错误状态,重新验证数据并在整个UI中传播更改,最后处理错误、中断和竞争条件(但老实说,实际上没有人处理这些事情)。

突变在remix中的作用:remix使用HTML形式。我知道你在想什么。

pffft。。。我正在构建一个网络应用程序,这永远不会奏效。

你可能会认为你即将看到的API看起来无法满足现代网络应用程序的需求。高度互动的网络应用程序一直是我的整个职业生涯,Remix的设计就是考虑到了它们。仅仅因为它看起来像过去的PHP,并不意味着它不能扩展到现代、复杂的用户体验。我们喜欢说remix是放大的,但它也缩小了。让我们回到过去,帮助你理解remix。

自从网络出现以来,一个突变被建模为一个表单和一个服务器页面来处理它。完全忽略Remix,它看起来是这样的:

<form method="post" action="/add-to-cart"><input type="hidden" name="productId" value="123" /><button>Add to Cart</button>
</form>
// on the server at `/add-to-cart`
export async function action(request) {let formData = await request.formData();return addToCart(formData);
}

浏览器通过表单序列化数据的POST导航到“/add to cart”,添加挂起的UI,并在完成后使用数据库中的所有新数据呈现新页面。

Remix的功能与HTML表单相同,只是使用了capital-F<Form>和路由上名为action的函数进行了优化(假设您的Next.js页面是他们自己的API路由)。它使用fetch而不是文档重载进行发布,然后使用服务器重新验证页面上的所有数据,以保持UI与后端同步。这和你在SPA中习惯做的事情是一样的,只是Remix为你管理一切。

除了表单和服务器端操作之外,不需要任何应用程序代码来与服务器通信变异。也没有应用程序上下文提供程序或全局状态管理技巧将更改传播到UI的其余部分。这就是为什么Remix捆绑包比Next.js捆绑包小近30%的原因,你不需要所有的代码来与你的“API路线”对话。

哎呀,我又撒谎了。这个代码实际上在Remix中有效。如果你使用小写字母<form>,浏览器会处理帖子,而不是Remix。适用于JavaScript加载失败的情况😅 (稍后会详细介绍)

你可以向Remix询问繁忙的微调器的过渡和进度,或者发布数据来创建乐观的UI,从而扩展到花哨的UI。模型是HTML表单,功能是你的设计师想出的任何东西。你不必完全重新规划你的实现,就可以说“没问题,我们可以做到。”

较小的捆绑包和简单的API突变也不是Remix在这里为您做的唯一事情。

由于Remix处理您与服务器的所有交互(包括数据加载和数据突变),因此它在web框架领域具有独特的能力,可以解决web应用程序的长期问题。

未处理的错误

当“添加到购物车”后端处理程序抛出错误时会发生什么?在这里,我们阻止对将项目添加到购物车的路线的请求,看看会发生什么。

Next.js POST失败

Next.js Failed POST 

什么也没发生。错误处理既困难又烦人。许多开发人员只是跳过它,就像他们在这里做的那样。我们认为这是一个糟糕的默认用户体验。

让我们看看remix会发生什么。

Remix Failed POST 

Remix处理应用程序中数据和渲染的每一个错误,甚至服务器上的错误。

你所要做的就是在应用程序的根目录下定义一个错误边界。您甚至可以变得更精细,只删除页面中出现错误的部分。

Remix能做到这一点而Next.js不能做到的唯一原因是,Remix的数据抽象并没有停留在如何将数据导入应用程序,以及如何更改数据上。

中断

用户经常在意外事件中点击两次按钮,大多数应用程序处理得不太好。但有时你有一个按钮,你完全希望用户点击得很快,并希望UI立即做出响应。

在此应用程序中,用户可以更改购物车中的商品数量。他们很可能会很快点击它,将数字增加几次。

让我们看看Next.js应用程序如何处理中断

Next.js Interruption 

要准确地看到发生了什么有点困难,但如果你擦洗视频控件,你可以更好地看到它。有一个奇怪的东西从5到6到5在中间。不过最后几秒是最有趣的。你可以看到,最后一个请求发送了着陆(转到4),然后几帧后,第一个请求发送着陆!数量字段从5跳到4,再跳到2,没有任何用户交互。有点难以信任的UI。

此代码没有管理竞争条件、中断或重新验证,因此UI现在可能与服务器不同步(这取决于2或4是最后一个到达服务器端代码)。管理中断并在突变后重新验证数据本可以防止这种情况的发生。

我明白了,处理比赛条件和干扰很难!这就是为什么大多数应用程序都不这么做的原因。Vercel团队是业内最有天赋的开发团队之一,甚至他们都跳过了。

事实上,当我们在上一篇博客文章中移植React Core团队构建的React Server Components示例时,他们也有同样的错误。

我之前说过,我们对网络标签非常狂热。让我们看看Remix是如何处理这一问题的。

Remix Interruption 

您可以看到Remix在中断时取消请求,并在POST完成后重新验证数据。这样可以确保整个页面上的UI(而不仅仅是这个表单)与表单在服务器上所做的任何更改同步。

你可能会认为,也许我们的应用程序比Next.js应用程序更注重细节。这些行为都不在应用程序代码中。这一切都内置于Remix的数据突变API中。(它实际上只是在做浏览器对HTML表单所做的事情…)

Remix中客户端和服务器之间的无缝集成和过渡是前所未有的。

Remix❤️ Web

在我们几十年的网络开发生涯中,我们记得它曾经是多么简单。在表格中放一个按钮,指向写入数据库的页面,重定向,获得更新的UI。这太容易了。

在设计Remix API时,我们总是首先关注平台。就像突变工作流程一样。我们知道HTML表单API+服务器端处理程序是正确的,所以我们围绕这一点进行构建。这不是目标,但一个非常惊人的副作用是,一个惯用的Remix应用程序的核心功能在没有JavaScript的情况下工作!

Remix Without JavaScript 

虽然以这种方式使用Remix是完全有效的,但我们并不希望您在没有JavaScript的情况下构建网站。我们有很大的雄心来构建令人惊叹的用户界面,你需要JavaScript来实现这一点。

与其说“Remix在没有JavaScript的情况下工作”,我们更愿意说“RemixforJavascript”。也许你的用户只是在页面加载JavaScript时进入了火车上的隧道。当它们弹出时,页面通常仍能正常工作。我们真的只是追求HTML的简单性,但最终我们得到了一个非常有弹性的框架。

我们也期待web平台来编写您的服务器端代码。Remix没有发明另一种新的JavaScript请求/响应API,而是使用Web Fetch API。要使用URL搜索参数,我们使用内置的URLSearchParams。为了处理表单数据,我们使用内置的FormData。

export function loader({ request }) {// request is a standard web fetch requestlet url = new URL(request.url);// remix doesn't do non-standard search param parsing,// you use the built in URLSearchParams objectlet query = url.searchParams.get("q");
}export function action({ request }) {// formData is part of the web fetch apilet formData = await request.formData();
}

你会发现,当你开始学习Remix时,你在MDN文档上花费的时间与Remix文档一样多,甚至更多。我们希望Remix能帮助您建立更好的网站,即使您不使用它。

在remix方面做得更好,在网络方面意外地做得更好。

这是我们的核心价值。虽然Remix应用程序的速度非常快,但我们实际上并没有过度关注性能,只是关注出色的用户和开发人员体验。我们向平台寻求问题的答案,使其更易于使用,并且性能通常会自行处理。

针对变化进行优化

既然你知道了这两个框架是如何运作的,那么让我们看看应用程序是如何应对变化的。我一直很喜欢“优化以适应变化”这句话,当我们设计Remix API时,我们经常谈到这一点。

更改主页

让我们考虑一下你想更改主页上的产品,那是什么样子的?Next.js中有两个选项:

  • 重建并重新部署您的应用程序。您的构建时间将随着商店中产品的数量线性增长(每个构建都必须从Shopify中提取每个产品的数据)。只需更改页脚中的拼写错误,就需要从Shopify下载每一款产品来部署更改。随着你的商店发展到成千上万的产品,这将成为一个问题。
  • 使用增量静态再生。Vercel认识到SSG中构建时间的问题,因此他们创建了ISR。当请求页面时,服务器会发送缓存的版本,然后在后台使用新数据重新构建它。下一个访问者得到的是新缓存的版本。

如果在部署时没有构建页面,Next.js将服务器呈现页面,然后将其缓存在CDN上。这正是HTTP stale-wile-revalidate所做的,除了ISR带有非标准的API和供应商锁定。

在Remix中,您只需使用Shopify更新您的产品,您的产品就会在缓存TTL内更新。您还可以在下午设置一个webhook来使主页查询无效。

这个基础设施比使用SSG需要更多的工作,但正如我们在本文中所看到的,它可以扩展到任何大小的产品目录、任何类型的UI(搜索页面),而且实际上比SSG更快,用户更多(我们可以缓存常见的搜索查询)。您也没有耦合到特定的主机,也几乎没有耦合到框架,因为Remix主要使用标准的web API来实现应用程序逻辑。

此外,我们认为在服务器上仅以一种方式加载数据会导致更干净的抽象。

缓存未命中怎么办?

这是一个很好的问题。服务器和HTTP缓存只有在您的网站获得流量时才能工作。事实证明,只有当你的网站也获得流量时,你的业务才能运作😳. 你不需要一天两次浏览页面就能快一秒,你需要一个邮件列表。

  • Remix中产品页面的空缓存命中率并不比Next.js网站中的搜索页面慢(在那里它不能使用SSG)。你上一次不搜索就在网上购物是什么时候?当缓存中充满了常见查询时,速度会更快。
  • 常见的登录页通常都会被准备好,然后Remix的预取会使下一个过渡瞬间发生。Remix可以预取任何页面,无论是动态页面还是其他页面,Next.js都不能。
  • 在使用SSG达到一定规模时,您需要切换到ISR。现在,在不属于上次部署的页面上,您也遇到了同样的缓存未命中问题

如果缓存未命中请求在你的访问中占很大一部分,那么获得100%的缓存命中率并不能解决你的业务:你没有技术问题,你有营销问题。

个性化

让我们看看另一个变化。想象一下,产品团队来找你,说主页正在更改,以显示与用户过去购买的产品类似的产品,而不是一组产品列表。

和搜索页面一样,SSG是不存在的,默认情况下你的性能也是如此。SSG的用例集确实有限。

几乎每个网站都有用户。随着网站的发展,您将开始向用户显示越来越多的个性化信息。每一次,它都会变成客户端获取。在某种程度上,您的页面的大部分都是客户端获取的,您的性能也随之下降。

对于Remix来说,这只是后端的一个不同的数据库查询。

想想电子商务食物链的顶端:亚马逊。整个页面都是个性化的。我们从一开始就知道结局。投资于能让你达到目标的架构,而不是产品团队调整主页时需要放弃的东西。

要旨

很容易错过Remix看似简单的<Form>+操作+加载程序API的强大功能,以及尽可能多地保留在服务器上的设计。它改变了游戏。这些API是Remix更快的页面加载、更快的转换、更好的用户体验(中断、竞争条件、错误)以及更简单的开发代码的来源。

Remix应用程序的速度来自后端基础设施和预取。Next.js的速度来自SSG。由于SSG的用例有限,特别是在功能和数据扩展方面,您将失去这种速度。

SSG和Jamstack是解决后端服务速度慢的好办法。最新一代的平台和数据库速度很快,而且只会越来越快。即使是支持这些应用程序的Shopify API也可以在200毫秒内从世界上几乎任何地方发送对查询的响应,我在除了南极洲之外的所有大陆都进行了测试!(这个月他来的时候,需要@chancedev帮我试试。)

老实说,跳过本文讨论的所有缓存策略并在服务器上的每个请求中使用Shopify API是完全可以接受的。而不是1.2秒的负载,它将是1.4。它将是1,而不是0.8秒。布普基斯。如果你有一个缓慢的后端API,投入你的时间使你的后端快速。如果你无法控制它,可以部署你自己的服务器并在那里缓存,这样你就可以为所有用户加速任何页面。

投资于后端将产生与SSG相同的性能结果,但它可以扩展到任何类型的页面。它将需要比SSG更多的初始工作,但从长远来看,我们认为这对您的用户和代码来说是值得的。

数据加载也只是故事的一半。在Remix中,您的数据抽象还可以封装数据突变。所有代码都留在服务器上,从而在浏览器中生成更好的应用程序代码和更小的捆绑包。

使用Next.js,您必须将自己的数据变异代码发送到浏览器,以便与API路由交互,并将更新传播到UI的其余部分。正如我们在这篇文章中看到的,即使是顶级球队也会因为失误、中断和比赛条件而陷入混乱。

你不是在忽略getServerSideProps吗?

有些人说你可以用getServerSideProps完成Remix所做的所有事情。这个问题来自于我们还没有机会很好地解释Remix!

如前所述,这肯定会加快搜索页面的速度。然而,您仍然需要处理数据突变。您将需要getServerSideProps、API路由和您自己的浏览器代码的组合,以便与它们进行通信以进行突变(包括错误处理、中断、竞争条件、重定向和重新验证)。我们在这里真正要说的是“你可以建立自己的remix”。的确,你可以。我们已经做到了。


 

原文:【前端开发】Remix与Next.jsicon-default.png?t=N7T8https://developer.chat/remix-vs-nextjs

欢迎收藏【架构师酒馆】或者【开发者开聊】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/177302.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据治理:数据交换与数据集成

数据交换 基本概念 数据交换是将符合一个源模式的数据转换为符合目标模式数据的问题&#xff0c;该目标模式尽可能准确并且以与各种依赖性一致的方式反映源数据。 早期数据交换的一个主要方向是在关系模式之间从数据交换的上下文中寻求一阶查询的语义和复杂性。2008 年&…

网络篇---第五篇

系列文章目录 文章目录 系列文章目录前言一、如何实现跨域?二、TCP 为什么要三次握手,两次不行吗?为什么?三、说一下 TCP 粘包是怎么产生的?怎么解决粘包问题的?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站…

进程(4)——进程地址空间【linux】

进程&#xff08;4&#xff09;——进程地址空间【linux】 一.什么是进程地址空间二.进程地址空间不是真实地址&#xff1f;三.物理地址与进程地址空间的关系&#xff08;整体部分&#xff09;四. 细节4.1 进程地址空间的本质&#xff1a;4.2 为什么要有进程地址空间&#xff1…

Mac 搭建本地服务器

文章目录 1 启动服务器2 服务器目录3 手机访问服务器3.1 手机和电脑连上同一个局域网( 或WIFI)3.2 找到电脑的ip地址 如下图所示3.3 手机打开 http://192.168.10.5/1.txt 4 关闭服务器5 参考文章 1 启动服务器 sudo apachectl start启动后访问 http://localhost/ 如下图所示即…

JavaWeb后端数据库MySQL的使用

JavaWeb MySQLSQL数据库设计 多表设计1对多1对1多对多 多表查询连接查询内连接外连接左外连接右外连接 子查询事务索引 MySQL MySQL数据模型 关系型数据库&#xff1a;建立在关系模型基础上&#xff0c;由多张相互连接的二维表组成的数据库。 SQL SQL&#xff1a;操作关系型数…

系列二十一、Spring中bean的创建顺序

一、概述 我们知道启动IOC容器时&#xff0c;Spring会为我们创建各种各样的bean&#xff0c;那么思考一个问题&#xff0c;bean的创建顺序是由什么决定的呢&#xff1f;答&#xff1a;bean的创建顺序是由BeanDefinition的注册信息决定的&#xff0c;这个其实很好理解&#xff0…

创建SpringBoot Helloword 程序详细步骤

本文档实现SpringBoot hello word 程序&#xff0c;翻译于Spring | Quickstart 目录 一、项目创建步骤1.1 创建项目1.2 添加代码1.3 运行 参考教程 一、项目创建步骤 1.1 创建项目 在官网Spring Initializr上创建项目 1.2 添加代码 在IDE中打开项目并在src/main/java/com/zo…

pinpoint链路跟踪运用及日志logback配置

本文将讲述pinpoint的安装&#xff0c;使用及与java logback 日志的集成。 介绍 是什么 是一款 APM监控工具(Application Performance Management/应用性能管理)基于java编写用于 大规模分布式系统 的监控&#xff0c;是 分析 大规模分布式系统 的平台基于google Dapper开发&…

Android Bitmap 模糊效果实现 (二)

文章目录 Android Bitmap 模糊效果实现 (二)使用 Vukan 模糊使用 RenderEffect 模糊使用 GLSL 模糊RS、Vukan、RenderEffect、GLSL 效率对比 Android Bitmap 模糊效果实现 (二) 本文首发地址 https://blog.csdn.net/CSqingchen/article/details/134656140 最新更新地址 https:/…

2021年03月 Scratch图形化(四级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共15题,每题2分,共30分) 第1题 运行如下图所示的程序后,以下描述正确的是? A:角色停留在(0,0)的位置,不会移动。 B:角色会在舞台上沿水平方向不停地左右往返移动,碰到边缘就反弹。 C:角色会向右沿水平方向…

【MVP矩阵】裁剪空间、NDC空间、屏幕空间

裁剪空间概述 裁剪空间是一个顶点乘以MVP矩阵之后所在的空间&#xff0c;Vertex Shader的输出就是在裁剪空间上&#xff08;划重点&#xff09; NDC空间概述 接上面&#xff0c;由GPU自己做透视除法将顶点转到NDC空间 两者的转换 透视除法将Clip Space顶点的4个分量都除以…

C语言SO EASY(ZZULIOJ1220: SO EASY)

题目描述 Superbin最近在研究初等数论&#xff0c;初等数论 是研究数的规律&#xff0c;特别是整数性质的数学分支。它是数论的一个最古老的分支。它以算术方法为主要研究方法&#xff0c;主要内容有整数的整除理论、同余理论、连分数理论和某些特殊不定方程。 是定义在正整数…

linux设置主机名

查看主机名&#xff1a;hostname 临时修改主机名&#xff1a;hostname 新主机名 [rootlocalhost ~]#hostname centos [rootlocalhost ~]#hostname centos 永久修改主机名&#xff1a; [rootlocalhost ~]#cat /etc/hostname localhost.localdomain

C#Backgroundworker与Thread的区别

前言 当谈到多线程编程时&#xff0c;C#中的BackgroundWorker和Thread是两个常见的选择。它们都可以用于实现并行处理和异步操作&#xff0c;但在某些方面有一些重要的区别。本文将详细解释BackgroundWorker和Thread之间的区别以及它们在不同场景中的使用。 目录 前言1. Backgr…

自动驾驶视觉感知技术

1、视觉感知 2、应用功能 3、视觉感知支持的功能 4、软硬件产品 5、DMS、手势识别、行为检测 6、DMS视觉检测 7、驾驶员离位检测 8、安全带检测 9、双手脱离方向盘检测 10、后排遗留物检测 11、360环视AVM倒车指引线MOD 12、盲区监测

上门预约互联网干洗店洗鞋店小程序开发

很多时候可能大家的衣服鞋子需要干洗&#xff0c;但又不想出门送去店里&#xff0c;大家就可以使用手机线上下单预约取货&#xff0c;会有专门的人上门来取衣服&#xff0c;让你能够轻松的进行洗护。 闪站侠洗衣洗鞋小程序&#xff0c;提供了足不出户就能预约人员上门去 衣送洗…

两部手机数据传输后备忘录不见了怎么回事

想必很多人都遇到过&#xff0c;当两部手机进行备忘录数据传输后&#xff0c;突然发现备忘录不见了&#xff0c;这让人不禁着急上火&#xff0c;我也曾经遇到过这种事情导致很多重要的内容都丢失了。 一般出现这种情况可能是因为&#xff0c;两部手机使用的是不同的云服务&…

中学课程辅导杂志中学课程辅导杂志社中学课程辅导编辑部2023年第10期目录

教育视点 核心素养导向下的初中化学大单元教学研究 陈玉霞; 3-5 核心素养下的英语大单元教学策略 马玲凤; 6-8 盲校初中语文课堂教学特点及教学策略 王瀚文;王彩云; 9-11 新课改背景下高中语文教学语言的运用探讨 王文静; 12-14《中学课程辅导》投稿&#xff1…

第二十章,多线程

创建线程 有两种方式&#xff0c;分别为继承Java.lang.Thread类与实现Java.lang.Runnable接口 继承Thread类 Thread常用的两个构造方法语法 public Thread&#xff08;&#xff09;&#xff1b; public Thread&#xff08;String threadName&#xff09;&#xff1b; 继承…

<Linux>(极简关键、省时省力)《Linux操作系统原理分析之Linux 进程管理 5》(9)

《Linux操作系统原理分析之Linux 进程管理 5》&#xff08;9&#xff09; 4 Linux 进程管理4.5 Linux 信号4.5.1 信号的作用和种类1.信号机制2.信号种类 4.5.2 信号的处理4.5.3 信号处理函数1&#xff0e;数据结构2&#xff0e; 处理函数 signal3&#xff0e;程序例 4 Linux 进…