盖茨比如何规避Next.js

这篇文章的作者(我们今天出版的翻译版本)是Antler的一名程序员。这家公司是一家全球性的创业公司。每年都会在Antler举行几次演示日,汇聚了来自世界各地的许多创业者和投资者。COVID-19周围的情况迫使鹿茸将其事件转换为在线格式。



该公司希望确保虚拟事件的访问者能够看到最重要的信息,而不会被任何事情分散注意力,也不会被困在任何地方。即,将初创企业的想法呈现给公众,以网页的内容表示。虚拟演示日可能会吸引相当多的听众。该受众群体的某些成员可能是第一次参加这样的活动。因此,该公司必须以最佳方式做所有事情,并提供代表初创公司的页面的高速加载。他们认为,只有高性能的渐进式Web应用程序(PWA,渐进式Web App)可以派上用场时,情况才是如此。主要问题是找到开发PWA的正确技术。


服务器渲染还是静态网站生成器?


首先,我将向您介绍该课程。我们所有的项目都基于React和Material-UI库。结果,我们最初决定不放弃该技术堆栈,这将使我们能够确保高开发速度并使新项目与我们现有的产品兼容。这个新项目与我们其他React应用程序之间的主要区别在于,它们的数据库是使用create-react-app创建的,并且已在客户端上完全呈现(CSR,客户端渲染)。特别是,这导致了这样一个事实,即在最初加载应用程序时,在项目JavaScript代码正在加载,处理和执行时,用户被迫观察空白的白屏。

我们需要一个不折不扣的性能水平。因此,我们开始考虑使用服务器端渲染(SSR,服务器端渲染)或静态站点生成器(SSG,静态站点生成器),以便尽快加载应用程序。

我们的数据存储在Cloud Firestore中,我们使用Algolia访问它们。这使我们能够在数据库字段级别上控制使用受限API密钥对数据的公共访问。这也提高了查询性能。根据经验,我们知道Algolia查询的速度比平常快,并且压缩的Firestore JavaScript SDK大小为86 KB。对于Algolia,为7.5 Kb

此外,我们希望使提供给客户的数据尽可能新鲜。这将帮助我们非常迅速地纠正可能会意外发布的错误数据。虽然SSG的标准做法是在项目的组装过程中实现对数据的相关请求,但我们希望在数据库中写入数据的频率很高。特别是,我们谈论的是管理员使用firetable界面启动的数据记录,并根据项目的创建者的倡议使用网络门户。这导致了项目的竞争性组装。此外,由于我们数据库的结构特征,较小的更改可能导致新的项目组装操作。这使我们的CI / CD管道效率极低。因此,每次用户请求加载页面时,我们都需要执行从存储库接收数据的请求。不幸的是,这意味着我们的解决方案不会成为“干净的” SSG项目的示例。

最初,我们的应用程序是在Gatsby的基础上创建的,因为我们已经使用了基于Gatsby构建的登陆页面,并且其中之一已经使用了Material-UI库。该项目的第一个版本形成了一个页面,该页面在加载数据时显示一个“骨架”。同时,第一个合格涂料(FCP)大约在1秒内。


下载页面的“骨架”并随后加载数据

该解决方案虽然很有趣,但是它有缺点,因为页面输出的数据是在客户端的主动下下载的:

  • 要查看该页面的内容,用户必须等待该页面本身的下载以及其中显示的数据,这些数据是通过4个向Algolia的请求获得的。
  • JS- . , React «» . DOM.
  • . , , .

结果,在一个漫长的周末中,我决定尝试使用Next.js创建的项目的SSR版本。对我来说幸运的是,Material-UI的文档中有一个Next.js的示例项目。因此,我不需要从头开始学习所有这些框架。我只需要仔细阅读本教程和文档的某些部分。我将应用程序转换为在服务器上呈现的项目。当用户请求页面加载时,服务器执行请求以填充页面所需的数据。此步骤使我们能够解决上述所有三个问题。这是两个应用程序选项的测试结果。


使用Google PageSpeed Insights研究应用程序的结果。左侧是Gatsby(SSG),右侧是Next.js(SSR)(原始图像

该项目的Next.js版本的FCP大约是其基于Gatsby的版本的FCP约3倍。该项目的Gatsby版本的Speed Index为3.3秒,而Next.js版本的为6.2秒。使用Next.js时,到第一个字节的时间(TTFB,到第一个字节的时间)为2.56秒,使用Gatsby时为10-20毫秒。

应当注意,该站点的Next.js版本已部署到另一个服务(此处我们使用了ZEIT Now和Firebase Hosting服务-这也可能影响TTFB的增加)。但是,尽管如此,很明显,尽管所有页面资料都是在大约同一时间加载的,但将数据上传操作转移到服务器使站点显得较慢。事实是,在项目的Next.js版本中,一段时间内用户只能看到空白的白页。


该屏幕截图显示了加载应用程序的两个版本。下载未同时完成。按下Enter键后,记录将同步,

这为我们在Web开发领域提供了重要的启示:您需要为用户提供视觉反馈。一项研究发现,使用骨架屏幕的应用程序加载速度似乎更快。

而且,此结果与您阅读最近几年有关Web开发的文章时可能会产生的心情不符。也就是说,我们正在谈论的事实是,使用客户的资源没有错,并且SSR并不是解决性能问题的全面解决方案。

静态网站生成性能:比较Gatsby和Next.js


尽管考虑中的两个框架Gatsby和Next.js分别具有生成静态站点和服务器呈现的能力,但在Next.js 9.3中改进对SSG的支持,这使其成为Gatsby的竞争对手。

在撰写本文时,Next.js生成静态站点的能力仍然很新鲜。她有一个多月了。在项目的第一页上仍会报告她。现在,对Gatsby和Next.js的SSG功能的比较不多(或者也许根本没有这样的比较)。结果,我决定进行自己的实验。

我将项目的Gatsby版本恢复到在客户端上下载数据时的状态,并进行了修改,以使应用程序的两个版本都具有完全相同的功能集。也就是说,我必须删除Gatsby插件负责的工作:SEO函数,生成网站图标,PWA清单。为了专门比较由框架创建的JavaScript包,我没有在项目中包含从外部源下载的图像和其他内容。这两个版本的应用程序均已部署在Firebase托管平台上。作为参考,基于Gatsby 2.20.9和Next.js 9.3.4创建了该应用程序的两个版本。

每个版本我在计算机上运行Lighthouse 6次。结果显示,盖茨比略有优势。


每个框架启动6个Lighthouse之后获得的平均值(原始图像

就整体性能评估而言,Next.js版本仅略低于Gatsby版本。 FCP和速度指数也是如此。应用程序的Next.js版本的“下一个潜在的优先输入延迟”略高于Gatsby版本。

为了更好地了解正在发生的事情,我转到了Chrome开发人员工具的“网络”标签。事实证明,在该项目的Next.js版本中,将JavaScript代码拆分为的片段数比在Gatsby版本中(不包括清单文件)多3个,但压缩后的代码小了20 KB。下载这些文件所需的额外请求是否可以远远超过较小捆绑包的好处,从而损害性能?


在该项目的Gatsby版本中,执行了7个请求以下载379 KB数据。在该项目的Next.js版本中,有12个请求下载359 KB数据(原始图像),

如果您分析JavaScript性能,则开发人员工具表示该项目的Next.js版本需要额外的300 ms才能进行首次渲染,并且该版本在“评估脚本”任务上花费了更多时间。在开发人员的工具中,该任务甚至被标记为“长期任务”。


使用Chrome开发人员工具的“性能”标签对不同项目选项的性能进行了分析(原始图像),

我比较了项目代码,以了解它们的实现中是否存在任何可能影响性能的差异。除了删除不必要的代码和与缺少TypeScript类型相关的更正外,唯一的区别是在移至页面的各个部分时实现了页面的平滑滚动。此功能以前是由文件引入的gatsby-browser.js,已被移至动态导入的组件。结果,此代码只能在浏览器中运行。 (我们使用了 smooth-scroll npm包,并且在导入时,他需要一个对象window。)这个问题可能是罪魁祸首,但是我只是不知道在Next.js中是如何处理的。

从开发人员的角度来看,盖茨比更方便


最后,我决定选择该项目的Gatsby版本。此外,在这里,我没有考虑盖茨比与Next.js SSG机制相比所表现出的很小的性能优势(我不会认真抓住0.6秒的优势吗?)。事实是,在该项目的Gatsby版本中,已经实现了许多PWA功能,并且我没有看到在应用程序的Next.js版本中再次实现它们的意义。

当我刚创建该项目的第一个盖茨比版本时,我能够快速向该项目添加一些有用的PWA功能。例如,要将SEO所需的自己的meta标签添加到每个页面,我只需要阅读手册。要为项目配备PWA清单,我只需要使用适当的插件。为了为该项目配备支持所有可用平台的favicon (在这种情况下仍然是一团糟),我什至无需做任何事情,因为favicon支持是负责清单的插件的一部分。很舒服!

在应用程序的Next.js版本中实现相同的功能将需要更多的工作。我将不得不寻找各种“最佳实践”的培训手册。无论如何,我会成功的事实不会给我带来任何好处。毕竟,该项目的Next.js版本在性能上与其Gatsby版本没有什么不同。另外,这就是为什么我决定直接禁用项目的Gatsby版本的相应功能,并将其与Next.js版本进行比较的原因。 Next.js文档比Gatsby文档更简洁(也许事实是Next.js小于Gatsby我真的很喜欢游戏化的Next.js教程 但是,更全面的Gatsby文档对于PWA的实际开发更有价值,尽管乍一看它看起来非常庞大。


盖茨比文档

确实,我不能对Next.js的优势保持沉默:

  • 多亏了Next.js的教程和简洁的文档,感觉这个框架比Gatsby的学习速度更快。
  • Next.js中使用的数据加载系统基于异步功能和Fetch API。结果,在开发Next.js时,开发人员没有感觉到需要学习GraphQL才能充分利用框架的功能。
  • Next.js TypeScript, Gatsby , ( ). Next.js , , , .

由于Next.js改进了对SSG的支持,因此该框架已成为功能强大的工具,允许在每个页面的层次上选择使用它的方法。它可以是SSR,SSG或CSR。

事实上,如果我能产生一个完全静态的形式这个应用程序,然后Next.js会更适合我,因为我可以用标准的Algolia JS-API,并可能继续加载数据的代码在同一个文件作为和组件代码。由于Algolia没有内置的GraphQL API,并且没有用于Algolia的Gatsby插件,因此在Gatsby中实现这种机制将需要将此代码添加到新文件中这违背了描述页面的直观声明方式。

关于提高项目绩效的其他方法


解决了选择框架的问题后,可以注意到,还有其他一些与框架无关的改善项目绩效的方法。这些改进很可能使Lighthouse项目的评分达到100。

  • 三月的 Algolia 邮件列表中,建议添加提示preconnect以进一步提高查询执行速度。(不幸的是,时事通讯中给出了错误的代码片段。这是正确的代码。)
  • . JS- CSS-, webpack- Gatsby. Gatsby . , , Netlify Amazon S3. , Firebase Hosting, , .
  • 我们在应用程序中使用由启动创建者上传的JPEG和PNG图像。我们不压缩和优化它们。改善我们应用程序的这一方面是一个很大的挑战,超出了该项目的范围。另外,如果所有这些图像都转换为WebP格式,那就太好了。结果,我们将只能使用一种高效的图形格式存储图像。不幸的是,与许多其他PWA功能一样,Safari WebKit开发团队对WebP支持很着迷。现在,它是唯一不支持这种格式的主流浏览器

摘要


如果我们简要总结一下我们在这里所说的话,那么我们可以这样说:

  • 客户端在数据加载期间页面的“骨架”版本的输出使用户感觉到网站操作比服务器在加载数据时查看空白页面时更快。
  • 该网站的gatsby版本仅比Next.js版本略快。但是,Gatsby插件系统和高质量的项目文档为开发人员增加了该框架的可用性。

亲爱的读者们!您是否使用静态网站生成器或服务器端渲染系统来加速项目?


All Articles