Qwik的Qase:First tti的爱
#javascript #网络开发人员 #qwik #性能

速度的需求:很难做正确的事情

我喜欢Qwik,it’s no secret,我不仅说这是因为它是由我工作的公司建造的。这是因为我感受到了它解决的问题的痛苦。我不是唯一的。

不久前,著名的网络开发人员和演讲者Tejas Kumar在此视频中发布了他对Qwik的第一印象:

他首先讲述了一个回溯的故事,当时他和他的同事考虑了更快地制作网络应用程序的方法。在视频的后期,他解释了尝试这种努力所需的一些艰苦工作。

我也不陌生。回到我使用以SEO为重点的Web应用程序的时候,我们还试图使其更快。为了查看任何形式的改进,需要做很多代码杂耍。

这是一个痛苦的过程,许多其他开发人员也可能感觉到了。

您可能想知道我们需要做什么以及我们如何处理它,但是稍后我们会做到这一点。首先,我们需要了解哪些内容会减慢应用程序。

为什么Web应用程序很慢

长话短说 Web应用程序很慢,因为我们运送了太多的JavaScript。

最近,即使是Dan ShappirNext Insurance的性能技术负责人和JS Jabber的共同主持人),在过去的一年中向我们展示了what the median origin page weight by framework was

Graph showing median origin page weight by framework was over the year. Trend shows JS bundle size growing.

让我们花点时间介绍一下。为什么许多JS会使Web应用程序慢慢变慢?

有几个步骤:

  1. 下载
  2. 分析
  3. 执行

这些都需要时间�,用户需要等待。对于任何人来说,这不是一个很好的经历。尤其是如果您的互联网易碎并且设备不是最新和最大的费用,则支付两倍或三倍的费用。

当您没有良好的用户体验时,您会放弃船舶,无论是购物车,注册流还是阅读这篇文章。该业务可能会忘记这些转换-ð°下厕所。

曾经变得更轻的事情,正如特哈斯在他的视频中展示了当前的Reddit网站与“old Reddit”的视频时所证明的那样。

在这里,我们可以看到“old Reddit”网络上的总js:
Screenshot of "old Reddit" network pane emphasizing transfer weight, resource weight, and load finish time.

对于“new Reddit"
这是相同的 Screenshot of "new Reddit" network pane emphasizing transfer weight, resource weight, and load finish time.

注意区别吗?

A screenshot showing the number differences for transferred JS, JS resources dowloaded, and load finish time between "old" and "new" Reddit.

这是永远的,这是不做任何事情的。 JavaScript用于添加交互性。但是我们得到了很多互动。

为什么有这么多JavaScript

我可以想到的一些原因:

  • 无论是格式日期还是某些动画库。
  • 第三方脚本(例如分析,聊天或您的营销团队都在GTM中都停留的任何营销团队。
  • 第一方代码。

随着开发人员的经验得到了改善,我们的JS捆绑尺寸越来越大,并且在过去的十年左右的时间里,它们一直在增长,如此图所示:
JavaScript bundle size growth over the years.

但是为什么它会稳定增长?我会说这是由于产品需求和对丰富互动体验的用户期望。 我们添加的功能越多,我们生成的代码越多,我们运送的JavaScript就越多。

此外,DX(开发人员体验)和UX(用户体验)之间存在一些相关性。为了更好地理解这一点,我们可以看一下最近的一次演讲,即Shai Reznik(国际发言人和HiRez.io的创始人)给出了:

UX/DX correlation over time by framework generation (slide courtesy of Shai Reznik)

此图显示,每当我们改进DX时,我们都会降解UX。

首先,我们有静态页面,可以轻松按需提供HTML文档。

此后,服务器可以将数据注入击中数据库(DB)的HTML模板以创建个性化体验,并将该响应发送回浏览器,并增加了加载时间。

然后,我们以jQuery da og dom manipulator的形式撒了javascript。

后来是Rich Internet Applications (RIA)的时代,该时代由Adobe Flash和Microsoft Silverlight等技术普及。这些被埋葬在我们的集体思想中,

之后是Gen 2 Web应用程序的后半部分,带有Spas的诞生(单页应用程序),这些应用程序由骨架,敲除,角,Angle,React,Vue等框架领导。

这是由Node.js和NPM的兴起,它节省了DevS的时间,因为它们可以轻松安装包装。但是,增加了捆绑包的大小,进而增加TTI。

根据Shai Reznik的说法,我们现在在Gen 2.5上,尽管Shawn @swyx Wang的作家,演讲者和Devrel可能具有a different definition。此外,Kent C. Dodds具有one of his own,它结合了最好的静态页面。动态服务器端渲染页以及客户端上的水疗体验。

An illustration showing how client side rendering and server-side rendering work.

但是,当前一代框架的警告是随着应用程序大小的增长,JavaScript捆绑包也随着Time To Interaction (TTI)的增长。

主要原因是水合,这是将行为附加到声明性内容以使其互动的过程。

我不会介绍什么是水合,因为Miško HeveryHydration is Pure Overhead中得到了很好的覆盖。

我们能做什么

改善Web应用程序上TTI的一种可能解决方案是代码分裂。这是一种大型代码库分为较小,更易于管理的块或模块的技术。

这可以通过减少需要立即加载的代码数量并允许根据需要加载代码的不同部分来改善应用程序的性能。

另一个是懒惰的加载。 JavaScript Lazy Loading是一种防御JavaScript资源的加载的技术,直到需要,可能会改善Web应用程序性能。

懒惰根本不是懒惰的

但是,这些方法是手动且乏味的。正如Tejas在他的视频中所说的那样,这是他和他的同事在试图提高性能时认为要做的事情。

我一次也尝试过这种方法。拧紧真的很容易。您必须考虑很多事情,并与块和缓存一起玩。

此外,您必须考虑如果存在网络连接错误会发生什么;那我们该怎么办?我们会预取吗?我们使用服务工作者吗?
An image of Russel Crow from the movie Beautiful Minds next to a chalk board looking confused.

水合:努力工作

此外,水合的过程可能会消除许多艰苦的工作效果,因为仍然需要整个引导阶段,其中包括热切加载所有这些懒惰的JS块。

就像在玩电子游戏一样,您的进度在一个级别上并收集战利品,但是随后您不小心死了,必须从Square One重新启动。

在传统框架中,要进行互动,它必须将事件侦听器附加到DOM上。在用户执行操作时,单击,鼠标移动和其他触发的事件。有两个问题:

  1. 框架需要知道需要附加事件处理程序
  2. 框架需要知道事件触发时应该发生什么。

要确定应将事件附加到哪里,框架必须下载所有可见组件并执行其模板。通过执行模板,该框架了解事件的位置,并可以使用DOM注册事件。

这将我们带到了第二点。如果触发事件,应该会发生什么?它需要用于事件处理程序的代码。

用户是否与“菜单”进行交互无关紧要。该代码仍然需要急切地加载。问题在于问题。

保湿力急切下载和执行代码。这就是我们的框架的工作方式。

A slide explaining why hydration is like replaying an app. Rendering runs twice. All logic needs to be dowloaded.

接下来是什么

部分水合

意识到网站启动性能确实很重要,该行业已经开始朝着正确的方向发展。

React 18和server components承诺在没有交互时仅向客户发送HTML,向浏览器提供更少的JavaScript。

Next.js 13实际上是当前支持RSC的唯一框架以及改善性能的更多优化。这绝对是一个改进,但它仍然要求开发人员按组件进行思考。

Astro与他们的岛屿建筑有不同的方法:

Astro Islands代表了前端网络架构的领先范式转变。 Astro将UI提取到页面上较小的隔离组件中。未使用的JavaScript被轻巧的HTML替换,保证了更快的负载和时间交互式(TTI)。— ASTRO网站

这很棒,因为它还允许您在几乎所有喜欢的前端框架中编写组件。您可以逐案进行岛屿互动,并通过控制水合的特定指令,称之为部分水合。

I myself use Astro for my blog,我真的很喜欢它。即使我以为我在不同的框架中写了不同的组件 - 我最终主要是编写Astro组件ð。

再次,这很棒,但是在任何框架中触发水合的警告 - 它将再次急切地加载您的JS。

简历:水合解决方案

Marko是正确方向的巨大飞跃。它具有流媒体,部分水合作用,可优化输出的编译器,并且运行时间很小。我还通过葡萄藤听到Marko V6也为框架增添了可靠性。

在理想的世界中,直到用户与页面的特定部分进行交互之前,没有JavaScript被下载和执行。如果用户单击“购买”按钮,则该框架应仅带来处理“购买”按钮所需的代码;它不必带上与“菜单”相关的代码。

问题并不是说JavaScript太多了。相反,必须急切地下载和执行JavaScript。 (正如我提到的那样,许多现有系统都有懒惰的加载,但仅适用于当前不在渲染树中的组件)。

理解恢复性

简而言之,我们在水合下运行代码,然后在客户端上运行代码。可重复性,意味着一次运行该应用程序,暂停执行,然后恢复我们在客户端上停止的位置。

就像VM的工作方式一样。虚拟机可以在操作系统上运行应用程序,例如文本编辑器,然后停止 - 移至另一台计算机,然后恢复。

A slide explaining resumability. Leverage what already ran on the server. Server serializes app state then it resumes.

可简历框架并不是什么新鲜事。近十年来,Google一直使用WIZ(Google的内部框架),该框架为Google搜索和照片提供动力。 Marko是来自eBay的框架,他们有望在其下一个版本中重新效能。

An image showing icons of replayable frameworks next to resumable frameworks.

但是,我们在这里不谈论其他框架,我们在这里要谈论一个尤其是Qwik的框架,这是第一个开源框架,其主要重点是重新固定的。

Qwik做了什么

Qwik采用了解决问题空间的新方法。这是我们用来将JS提供给浏览器的方式的范式转变。

让我们谈论一秒钟。大多数框架启动所需的JS类似于100KB-200KB(未限制的,而不是GZZE)。即使您进行代码拆分和懒负载,它也从该起点开始,然后加载更多的JS。

Qwik按需加载JavaScript。它以JS的1KB常数开始,直到进行用户交互。将其放入更多的计算机科学术语中,most frameworks are O(n), while Qwik is O(1)

A graph showing JS execution over time per number of user interactions - traditional frameworks compared to resumable frameworks. The Y axis shows executed JS, the X axis shows time & number of user interactions.

如果您不添加互动,则无需加载更多的JavaScript。

渲染性能很重要,但是当我们查看真实的用户体验时,互动的时间更重要。
A graph and a table showing startup performance on todo application in different frameworks with the Mitosis logo in the bottom left.

RESMUMAISIOS解决了交互式(TTI)问题,因为在启动时(设置全局侦听器之外)没有什么可以做的框架。该应用程序即时准备就绪。

与其他框架相比,Qwik认为捆绑,序列化和预取用是核心竞争力,并且具有快速启动性能的整体方法。这使其可以重新恢复。

让我们在行动中看到它!

Qwik在行动中

一个例子

让我们看一些代码的样子:

import { component$, useSignal } from '@builder.io/qwik';
import type { DocumentHead } from '@builder.io/qwik-city';

export default component$(() => {
  const count = useSignal(0);
  return (
    <div>
      <h1>
        Counter is {count.value} <span class='lightning'>⚡️</span>
      </h1>
      <button onClick$={() => count.value++}>Increment</button>
    </div>
  );
});

export const head: DocumentHead = {
  title: 'Welcome to Qwik Demo',
  meta: [
    {
      name: 'description',
      content: 'Qwik site description',
    },
  ],
}; 

You can see the result here. (video).

出于演示目的,我不会进入如何启动QWIK项目。有关Qwik,check out the Qwik docs或我们的Stackblitz Qwik Starter的更多信息。

有关此演示的代码,请查看Qase for Qwik GitHub repo

我们所做的是在QwikCity项目中创建一个简单的计数器组件,这是Qwik的元框架。基本上,它就像Sveltekit的Sveltekit一样,或SolidStart for Solid。它通常负责路由和构建。

如果您来自React(或固体),则可以看到以上许多看起来很熟悉。当Qwik使用JSX时,您应该直接感到在家。信号([useSignal](https://qwik.builder.io/docs/components/state/#usesignal))是一个反应性状态,类似于Solid.js signals,它由具有单个属性(signal.value)的对象组成,该对象在更改后将更新任何使用它的组件。同样,useStore几乎与信号相同,但接受对象作为参数,然后变为反应。

要注意的第二件事是component$onClick$之后的$符号。这就是所谓的a symbol in Qwik.,这些是优化器将代码分为零件的提示,以后可以智能地加载。重要的是要注意,只能在懒惰的边界中使用可序列化的数据。

See this video for an illustration of JS loaded in chunks

QWIK仅加载用户需要时需要的JavaScript

如果我们返回我们的柜台示例,DevTools显示了这一点(video)。

那里发生了什么?

在DevTools的Network窗格上,我选择仅显示JS请求。首先,我们可以看到两个文件:clientenb.mjs-这些是来自Vite的文件 - 我们的Dev Server,它还为Qwik和Qwikcity提供动力。为了隐藏这些文件,我们可以看到生产构建所提供的实际JS,我们可以过滤任何具有vite的路径。在隐藏了所有与Vite相关的文件之后,我再次刷新了Refresh(使用cmd + R),然后我们可以看到。没有下载JavaScript! ðÖ

然后,当我继续单击Increment按钮时,真正的魔术会发生!下载了两个文件,并且该按钮实际上有效并增加了我们的计数。它的优点在于,现在无需再加载JS! Qwik将代码分为单独的文件,可以根据需要加载。

让我们回顾一下这些文件是什么:

  1. core.mjs?v=a2bc250a-此文件是Dev Server(Unized)的主要QWIK核心运行时脚本。将其分解是另一个职位的主题。

    A screenshot of devtools network pane showing the downloaded JS core runtime script.

  2. routes_component_div_button_onclick_gurwhjlhap8.js-此文件实际上是处理我们的信号和onClick的原因(如名称所示,然后是哈希)。让我们看一下此文件的内容:

    A screenshot of devtools network pane showing the downloaded JS onClick script.

    在这里,我们有一个变量,该变量引用一个函数,该函数从useLexicalScope()钩中提取计数变量,然后返回一个增量count.value。 useLexicalScope()钩是Qwik检索反应变量参考的方式,无论是商店还是信号。

现在为HTML:

a screenshot of devtools HTML pane showing the added HTML attributes Qwik puts in.

我们可以看到对脚本的引用在哪里。

,然后我们可以看到更多信息存储在哪里:

a screenshot of devtools HTML pane showing the JSON data Qwik puts inside a script tag.

最重要的是,Qwik附加了事件听众,以便在需要加载某些东西时告知它。它还可以说出更可能使用JS并将其预取。例如,它将在新闻通讯之前加载您的购物车代码。

恢复行动

A graph showing other tools and Qwik's start up process. The X axis shows time, the Y axis labels other tools and Qwik. Courtesy of Tejas’s video.

其他工具需要做很多事情才能进行交互。在大多数情况下,Qwik仅下载html。

正如我们上面介绍的那样,我们在DOM中存储了信息,但它不仅是信息,而且序列化。 Qwik在服务器上运行并生成信息,序列化并停止。当服务器将HTML发送到客户端时,它具有所有信息。

有点像视频,您正在流式传输:

您可以在浏览器中恢复应用程序。

然后,您甚至可以及其所有状态暂停它,然后在另一个浏览器ðä(video)上恢复它

该视频刚刚发生了什么? ð¥´

  • 我在浏览器A。
  • 上与该应用进行了互动
  • 用$ 0.qwik.pape()暂停了该应用程序(DevTools中的$ 0是选择您重新检查的元素的一种方式),它在元素上运行,这是一个Qwik容器。
  • 复制了html。
  • 打开了一个新的浏览器(Safari,并不重要)。
  • 去了我们的应用程序,我再次以0状态获得了柜台。
  • 删除了html。
  • 粘贴了停顿的应用html。
  • 该州在新的浏览器ðºð½。
  • 中恢复了状态
  • 一切仍然是互动的。

如果这不打扰您,我不确定会怎样。打开的用例是无止境的。

只要Qwik加载程序运行,当您从一个Qwik移动到另一个Qwik或一个Qwik容器时,您就可以转移状态。

仔细考虑。

Qwik暂停

因此,我们谈论了为什么,什么和如何。为什么在这一点上我们需要新的范式?为什么您应该考虑使用Qwik?它是如何工作的?我们将介绍一些很酷的功能。

,但我们仍然没有展示它的快速和表现。

让我们挖。

测量性能

如今,大多数人使用Google Lighthouse,Page Speed Insights或GoodOlâWebPageTest测量网络应用程序和网站性能。

能够比较一个网络应用程序,最好将苹果与苹果进行比较。因此,为此,我们将查看Builder.io网站。特别是主页。

“为什么?”你可能会问。因为Builder主页有2个版本:

  1. qwik
  2. next.js(v10)

考虑到最近3个版本中的下一个有重大改进,这是我们拥有的最接近内容和功能的东西。

为了渲染旧的next.js版本,我们有一个查询参数,因此当我们击中http://www.builder.io/?render=next时,我们会得到它。

要比较两者,我运行了WebPageTest on both versions of our home page(移动4G美国测试配置)并使用了比较功能。

An image of the filmstrip output from WebPageTest of Builder.io's Next.js site version next to Qwik site version depicting load time.

马上,next.js站点开始加载视觉内容,而Qwik几乎显示了2.5秒后的所有内容。

An image of the filmstrip output from WebPageTest of Builder.io's Next.js site version load time.

next.js版本在9.5秒后全加载。

现在让我们查看所有时间安排(请注意Qwik版本是红色的,next.js为蓝色):

A screenshot of the timings graph from WebPageTest comparing Builder's Next.js site version vs Builder's Qwik site version.

请注意,底部的tti指标并不是下一个版本。因此,我对此进行了页面速度洞察力:

A screenshot of Lighthouse score for Builder's Next.js site version version. The performance score is 33.

这种运行奏效,但是我尝试了许多失败的跑步。而且,正如我们所看到的那样

仍然是从Google Chrome User Experience Report(简称Crux)获得大量实际用户性能数据的初期,以显示Qwik的表现。但是有一些:

A grpah of metrics from Crux that shows the percentage of good CWV scores. Arrows pointing at Qwik lines and table data. The Y axis is origins having good CWV, the X axis is a timeline from January 2020 to September 2022.

是的,一个高达4的是在选择流行前端技术时显示在报告中的网站数量,但这有些指示。

结论

Qwik是由3个表演书呆子(他们说的,而不是我ð)制造的,它们的腰带有4个前端框架。

An image of the Qwik team: Misko Hevery, Manu Almeida, and Adam Bradley with the title "Built by Performance Nerds".

他们受到了令人难以置信的工程师所做的所有最新框架和辛勤工作的启发,因此,他们带来了这些框架的许多喜爱功能。

他们得出的一般认识是Qwik的创新,是所有Spa Frameworks的服务器端渲染是事后的想法。在某个时候,您击中了水合瓶颈,而您根本无法在开发人员中进行优化。

很容易将东西放在一起,但是很难将事情分开。

Qwik不仅支持SSR/SSG/SPA,还是一种混合体。您可以选择适合您需求的哪个。

这篇文章中的演示在证明Qwik的完整能力方面没有公正性 - 这还不够现实。它在高度互动的大型应用程序中发挥了作用,因为它的性能与我们的简单示例相同。应用程序具有多少个代码的功能或行都不重要。

Qwik的最佳功能之一是,它可以完成正确的工作。您不必努力工作才能获得良好的表现。这是一个给定的,只是它的性质。

除此之外,Qwik还有更多功能:

Qwik和Qwikcity仍在Beta中,但社区开始开花。 构建快速网络应用程序从来没有比Qwik更容易。那你还在等什么?尝试一下,团队正在寻找更多反馈ð。