前端渲染模式与框架简介

Google制定Web指标

2022年谷歌提出的三个web核心指标, 目前已经成为衡量web页面性能的标准。

  • Largest Contentful Paint (LCP) :最大内容绘制,测量加载性能。为了提供良好的用户体验,LCP 应在页面首次开始加载后的2.5 秒内发生。

  • First Input Delay (FID) :首次输入延迟,测量交互性。为了提供良好的用户体验,页面的 FID 应为100 毫秒或更短。

  • Cumulative Layout Shift (CLS) :累积布局偏移,测量视觉稳定性。为了提供良好的用户体验,页面的 CLS 应保持在 0.1. 或更少。

如果都不按照Google标准来怎么办? 会被认为是对用户交互不优化的,给网站打分低点,PR值给他调低,让他在搜索引擎中消失。 😁

CSR框架发展

CSR框架:当前 React 和 Vue主流框架。

使用了VirtualDom 和 真实的DOM结构一一对应。给客户端的只有空的root节点,在客户进行Hydrate ,在客户端需要Runtime,去构建VirtualDom,绑定对应事件再去响应用户操作。

水合是指在客户端恢复服务端渲染出的应用程序的过程。这包括复用服务端渲染的 DOM 结构、持久化应用程序状态、传输服务端已经获取到的应用程序数据,还有一些其他过程。

CSR架构设计对 LCP 和 FID 指标不太好,如果在一些B端(管理平台),这俩指标要求不高情况下也是没问题的。

CSR如何进行性能优化

React 和 Vue 使用SSR方式优化

React 和 Vue 在前期都实现了服务端渲染,可以在服务端对页面进行水合,这样就会在html中就会存在一些初始化好的节点。

SSR对指标的影响?
LCP缩短了, 但是FID指标会增长。(用户看到页面,可交互的时间提前)

SSR会带来什么弊端吗?

  • SSR基本上就离不开 Node.js类型的Server,注意压测。

  • SSR有可能会导致白屏,因为用户的首屏短了,用户可操作时间提前,导致Hydrate处理 和 用户操作产生的事件处理产生冲突,尤其是在抢购场景。

  • 对开发的要求越来越严格,有可能导致服务端的渲染的节点 和 客户端不匹配,前端会出现闪屏。

React18 性能优化

可以参考文章: https://juejin.cn/post/7257410745636913207

  1. React 应用程序中引入了并发渲染。用来优化客户端渲染,保证 FID指标的提升。

并发模式将一次渲染任务分解成多个小块,并通过 React 中的调度器(Scheduler)来优化执行顺序和时间,从而降低了单次渲染所需的计算资源和时间,提高了应用程序的性能。

基于 fiber 架构实现的,fiber为状态更新提供了可中断的能力。(fiber本质上讲渲染计算的最小单元)

有个高中生开发出Million.js, 它是一个极快且轻量级(<4kb)的虚拟DOM,可以使 React Component 速度提高70%, Million 与 React 一起工作,Million.js 通过使用一个微调的、优化的虚拟DOM, 减少了React的开销。

简单讲:并发模式可以 每 5 毫秒返回主线程,看看是否有更重要的任务需要处理,例如用户输入,甚至渲染另一个对当时的用户体验更重要的 React 组件。通过不断返回主线程,React 能够使此类渲染成为非阻塞并优先处理更重要的任务。 并发渲染器能够在后台“同时”渲染组件树的多个版本,而无需立即提交结果。

  1. Suspend

React 一次性完成树的 hydration(render)。这意味着,一旦它开始 hydrate(本质上是调用你的组件函数),React 就不会停止 hydration 的过程,直到它为整个树完成 hydration。因此,你必须等待所有的组件被 hydrated,才能与任何组件进行交互。

<Suspense> 组件。引入它是为了支持客户端进行惰性加载代码,可以将它与服务器渲染结合起来。

  1. Server Component (服务端组件)

SSR(HTML) 或者 CSR: 都是基于这样一个事实:同步 React 渲染器需要使用附带的 JavaScript 包在客户端重建组件树,即使该组件树已经在服务端可用。

React Server Components 允许 React 将实际的序列化组件树发送到客户端。客户端 React 渲染器理解这种格式,并使用它来高效地重建 React 组件树,而无需发送 HTML 文件。

默认情况下,React不会对React Server Components进行水合。这些组件不应该使用任何客户端交互,例如访问window对象或使用像useState或useEffect这样的hook。

要将组件及其导入添加到 JavaScript 包中,并发送到客户端使其具备交互功能,可以在文件顶部使用 use client 指令。这告诉打包工具将该组件及其导入添加到客户端包,并告知 React 在客户端进行水合以添加交互性,这种组件称为客户端组件。

例如:下面的RSC组件的结果

0:["$","div",null,{"children":[["$","h1",null,{"children":"I'm a React Server Component!"}],["$","h5",null,{"children":["Click ",["$","a",null,{"href":"/rsc","children":"here"}]," to see the RSC payload"]}]]}]

与普通的客户端组件相比,规范所规定的主要限制:

  • 不使用状态(例如,不支持useState() )。为什么?因为组件只运行一次,结果流向客户端;也就是说,组件不在客户端上运行,保持状态。

  • 没有像useEffect() 的生命周期事件。同样,因为该组件不是在浏览器中执行的,没有事件等。

  • 除非你在服务器上进行polyfill,否则就没有DOM等仅适用于浏览器的API。特别是考虑到fetch API,服务器端的渲染引擎通常提供一个polyfill,这样服务器端的功能看起来就像浏览器的API调用。

  • 没有依赖状态或效果的自定义钩子,也没有依赖浏览器专用API的实用函数。

React服务器组件支持的客户端组件所不支持的功能:

  • 使用纯服务器的数据源,如数据库、内部服务和文件系统。简而言之,组件可以完全访问它所处的节点环境。

  • 使用服务器钩子。对服务器端能力的访问,如文件系统,可以用钩子包装起来,与普通钩子一样的精神来分享功能。

  • 能够渲染其他服务器端组件、本地元素(div、span等)和客户端组件。

相关思考:

  • RSC和SSR是不是等同的概念?

RSC 和 SSR 不是等同的概念,尽管它们都在服务端运行且名称中均包含“Server”。SSR 是一种技术,通过模拟环境将 React Dom 树渲染成原生 HTML 并返回给客户端。无论是服务器组件还是客户端组件,都会以相同的方式渲染为原始 HTML。

  • 那我直接使用SSR将页面直接渲染出来可以吗? 可以的。

当服务器的评论数据准备好后,React 会将额外的 HTML 发送到同一个流中,以及一个最小的内联<script>标签以将该 HTML 放在“正确的位置”:

<div hidden id="comments">
  <!-- Comments -->
  <p>First comment</p>
  <p>Second comment</p>
</div>
<script>
  // This implementation is slightly simplified
  document.getElementById('sections-spinner').replaceChildren(
    document.getElementById('comments')
  );
</script>

思考:这种方式下,外部能和这个SSR组件进行交互吗?

Vue3 性能优化

在编译阶段做优化,因为Vue有模版<template>,存在模版编译时。

通过 比如静态提升、更新类型标记、树结构打平,就是将模板中的静态部分和动态部分作一些分离,避免在difff阶段一些无意义的操作。 这样用于diff的数据少了,效率自然高了。

我们称Vue的这种方式为: 动静结合.Vue 深谙中庸之道,在它身上很难找出短板。同时保留了 Virtual DOM 和运行时 Reactivity,让它兼顾了灵活和普适性。

相关知识: Vue开发版本和生产版本区别:

  • 完整版:同时包含编译器和运行时的版本。

  • 编译器:用来将模板字符串编译成为 JavaScript 渲染函数的代码。

  • 运行时:用来创建 Vue 实例、渲染并处理虚拟 DOM 等的代码。基本上就是除去编译器的其它一切。

例如: vue-loader,就是将Vue文件里的HMTL转为h函数。编译部分占了40%得体积。

更多参考: Vue开发版本和生产版本区别

性能提升主要做在编译阶段

静态标记,其作用是为了会发生变化的地方添加一个flag标记,下次发生变化的时候直接跳过。

静态提升,Vue3中对不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用。

小结

React 和 Vue 都是基于 Runtime 的框架,即框架本身有很多的代码,且都会打包到最终的产物中被发送到用户的浏览器里执行,当用户需要在页面上执行操作改变组件的状态时,框架的 Runtime 会根据新的组件状态(State)计算(Diff)出需要更新的DOM节点从而更新View。

Angular、React、Vue 等 Big Runtime 的框架体积都比较大,在首屏加载的时候就需要加载框架的JS文件并且执行相关的代码,那么就会产生一定的性能开销,尤其是弱网和低性能手机,性能影响就会越大。

Precompile 编译方案(Svelte, Solidjs)

看下下图,Precompile框架是如何做优化的。

React、Vue 这些以 Virtual DOM 为主的渲染方式,通常只能做到组件级别的精细化渲染。

而次世代的 Svelte、Solidjs 不约而同地抛弃了 Virtual DOM,采用静态编译的手段,将「声明式」的视图定义,转译为「命令式」的 DOM 操作。 (所有的事件绑定我在预编译阶段都 直接变成了对Dom的操作)

不需要再额外引入一个所谓的框架运行时!

这种框架的设计对指标的影响是: FID 指标大大缩短了。因为通过预编译阶段大大减少了runtime的事件,LCP指标可能会变大。

Svelte框架

先看看尤雨溪对他评价:
这个框架的 API 设计是从 Ractive 那边传承过来的(自然跟 Vue 也非常像),但这不是重点。Svelte 的核心思想在于『通过静态编译减少框架运行时的代码量』。举例来说,当前的框架无论是 React Angular 还是 Vue,不管你怎么编译,使用的时候必然需要『引入』框架本身,也就是所谓的运行时 (runtime)。但是用 Svelte 就不一样,一个 Svelte 组件编译了以后,所有需要的运行时代码都包含在里面了,除了引入这个组件本身,你不需要再额外引入一个所谓的框架运行时!

当然,这不是说 Svelte 没有运行时,但是出于两个原因这个代价可以变得很小:

  1. Svelte 的编译风格是将模板编译为命令式(imperative) 的原生DOM操作。

  2. 对于特定功能,Svelte 依然有对应的运行时代码,比如组件逻辑,if/else 切换逻辑,循环逻辑等等... 但它在编译时,如果一个功能没用到,对应的代码就根本不会被编译到结果里去。

Svelte框架的弊端:

  1. 代码量变大了。同样的组件模板,这样的 imperative 操作生成的代码量会比 vdom 渲染函数要大,多个组件中会有很多重复的代码

  2. Svelte 在大型应用中的性能还有待观察,尤其是在大量动态内容和组件嵌套的情况下。它的更新策略决定了它也需要类似 React 的 shouldComponentUpdate 的机制来防止过度更新。另一方面,其性能优势比起现在的主流框架并不是质的区别,现在大部分主流框架的性能都可以做到 。

  3. Svelte 的编译策略决定了它跟 Virtual DOM 绝缘(渲染函数由于其动态性,无法像模板那样可以被可靠地静态分析),也就享受不到 Virtual DOM 带来的诸多好处,比如基于 render function 的组件的强大抽象能力,基于 vdom 做测试,服务端/原生渲染亲和性等等。这一点在我看来比较关键。让我在一点点性能和 Virtual DOM 之间做抉择的话,我还是会选择 Virtual DOM。Vue 3 在保留 Virtual DOM 灵活性的前提下基于模版对渲染函数做 AOT 优化,性能已经做到跟 Svelte 很接近。

总体评价就是: "That would make it technically SvelteScript, right?"
翻译过来就是:“svelte 是造了个编译器吗?”

举个🌰:

Svelte编译代码时,会把模版编译成直接可执行的javascritp代码

image.png

当name发生变化时(产生了脏数据),会调用t1这个原生DOM节点进行更新。 set_data是封装的原生的javascript操作DOM节点的方法。

关于Svelte记录脏数据的方式:用得是位掩码(bitMask) 感兴趣得同学可以学习下这个算法。

关于Svelte学习可以参考:

公司开源的Markdown编辑器

Svelte 和 SolidJS 等预编译框架解决了 Runtime 和 VDOM 的问题,没有解决了 Hydration 的问题。

SolidJS框架

支持现代前端特性,例如:JSX, Fragments, Context, Portals, Suspense, Streaming SSR, Progressive Hydration, Error Boundaries和Concurrent Rendering

初看SolidJS和React写法几乎没上差异。极大了保持了用户的习惯。

编译时大不同
React的编译时很薄,基本只是编译JSX语法。

而SolidJS则采用了类似Svelte的方案:在编译时,将状态更新编译为独立的DOM操作方法。

看下面的编译🌰:

image.png

上面的🌰中可以

  1. 提前编译,更小的包体积,尺寸小。 (使用React时,即使没有用到Hooks,其代码也会出现在最终编译后的代码中。并且在SolidJS中,未使用的功能不会出现在编译后的代码中。)

  2. 响应式原理,精准更新对应的值。

  3. 直接使用浏览器的 DOM, 没有虚拟 DOM, DOM diff 一整套算法。

基于发布-订阅的模式实现响应式。

辛劳苦干React

有一个可能反直觉的知识:React并不关心哪个组件触发了更新。

在React中,任何一个组件触发更新(如调用this.setState),所有子组件都会重新走一遍流程。因为需要构建一棵新的Fiber树。为了减少无意义的render,React内部有些优化策略用来判断组件是否可以复用上次更新的Fiber节点(从而跳过render)。

同时,也提供了很多API(比如:useMemo、PureComponent...),让开发者告诉他哪些组件可以跳过render。

如果说,SolidJS的更新流程像一个画家,画面中哪儿需要更新就往哪儿画几笔。

那么React的更新流程像是一个人拿相机拍一张照片,再拿这张照片和上次拍的照片找不同,最后把不同的地方更新了。

Svelte 和 SolidJS 等预编译框架解决了 Runtime 和 VDOM 的问题,其实没有解决了 Hydration 的问题。

SSR(Qwik, Nextjs)

Qwik

号称世界上第一个 O(1) 的 JavaScript SSR框架

第一步我们需要在服务端获取对应页面的 HTML 页面,大多数情况(非纯静态页面)就需要在服务端调用用对应渲染方法渲染出 HTML 页面。

那么,如果我们能在第一步渲染 HTML 页面时,就添加对应的事件处理。后续的 3 步是不是完全可以省略下来了对吧。【是不是有什么办法,水合延迟到用户交互的时候?】

再看Hydration 造成的开销

首先针对于 Hydration 的过程,我们提过到首先会在服务器上进行一次静态 HTML 渲染,之后当 HTML 下发到客户端后又会再次进行 hydrate 的过程,在客户端进行重新执行脚本添加事件。

Hydration 过程的难点就在于我们需要知道需要什么事件处理程序,以及将该事件处理程序附加在哪个对应的 DOM 节点上。

这个过程中,我们需要处理:

  • 每一个事件处理程序中的内容,绝大多数框架中的状态都做为闭包函数保存在内容中。所以需要 hydration 的过程来重新获取状态。

  • 其次,在搞清楚了每个事件处理函数的内容后。我们也需要将对应的事件处理函数附加到对应的 DOM 节点上,同时还要确保该监听器的正确事件类型。

更加复杂每个事件处理函数中的内容是一个闭包函数,这个函数内部需要处理两种状态,APP_STATE 以及 FRAMEWORK_STATE

  • APP_STATE:应用程序的状态。简单来说应用程序的状态就是 HTML 事件中的各个状态事件,如果不存在这些事件状态那么所有的内容都是没有任何交互效果的。

  • FRAMEWORK_STATE:框架内部状态。通常我们会利用诸如 React 或者 Vue 等框架进行接替渲染。如果没有 FRAMETER_STATE,框架内部就不知道应该更新哪些DOM节点,也不知道应该在什么时候更新它们。

通俗来说 Hydration 就是在客户端重新执行 JS 去修复应用程序内部的 APP_STATE 以及 FRAMEWORK_STATE

新的IDEA

在CSR的前三个阶段可以被称为 RECOVERY 阶段,这三个阶段主要是在重建你的应用程序。

当从 Server 端下发的 HTML 静态页面后,我们希望它是具有交互效果的 HTML 正常应用程序。

那么此时 hydartion 的过程必须经历下载 HTML 、下载所有相关 JS 脚本、解析并且执行下载的 JS 脚本。

RECOVERY 阶段是和 hydartion 的页面的复杂性成正比,在移动设备上很容易花费 10 秒。

由于RECOVERY是昂贵的部分,大多数应用程序的启动性能都不是最佳的,尤其是在移动设备上。

前三个阶段被称为 RECOVERY 的阶段其实是完全没有必要的,因为在服务端我们已然渲染过对应的 HTML ,但是为了应用程序的可交互性以及服务端仅保留了静态的 HTML 模版导致不得不在 Client 上继续执行一次 Server 端的逻辑。

总而言之,hydration 其实是通过下载并重新执行 SSR/SSG 呈现的 HTML 中的所有 JS 脚本并执行来恢复组建中的事件处理程序。

同一个应用程序,会被发送到客户端两次,一次作为 HTML,另一次作为 JavaScript。

此外,框架必须立即执行 JavaScript 以恢复在服务器上被丢掉的 APP_STATEFRAMEWORK_STATE。所有这些工作只是为了检索服务器已经拥有但丢弃的东西!!

Resumability: 更加优雅的 hydartion 替代方案

所以为了消除额外的开销,我们需要思考如何避免重复的 RECOVERY 阶段。同时还要避免上面的第四步,第四步是执行脚本后给现有的 HTML 附加正确的事件处理程序。

qwik 中提出了一个全新的思路来规避 RECOVERY 带来的外开销:

  1. 将所有必需的信息序列化为 HTML 的一部分。
    qwik 将需要的状态以及事件序列化保存在 Server 端下发的 HTML 模版中,需要序列化信息需要包括WHAT(事件处理函数内容), WHERE(哪些节点需要哪些类型的事件处理函数), APP_STATE(应用状态), 和FRAMEWORK_STATE(框架状态)。

  2. 依赖于事件冒泡来拦截所有事件的全局事件处理程序。
    qwik 中事件处理程序是在全局处理的,这样我们就不必再在特定的 DOM 元素上单独注册所有事件。

  3. qwki 内部存在一个可以延迟恢复事件处理程序的工厂函数。
    该工厂函数主要用于处理 WHAT 阶段,也就是用来识别某个事件处理函数中应该存在什么脚本逻辑。

Resumable 对比 Hydration 明显可以省略不需要后三个阶段,直接获取 HTML 后页面其实就已经准备完毕,这无疑对于性能的提升是巨大的。

简单来讲Qwik的工作原理就是在服务端序列化 HTML 模版,从而在客户端延迟创建事件处理程序,这也是它为什么非常快速的原因。

看编译后🌰:

image.png

例如下面的按钮+1的组件

 // 转换前
 <button onClick$={() => {
     state.count += 1;
   }}

// 转换后
 <button onClick$={qrl('./chunk-c.js', 'Home_onClick', [store, props])}

简单讲就是:把事件单独的打包成一个执行的JS逻辑,用户点击的时候,将文件下载并且执行。

我们可以看出来,qwik的核心思路还是通过更加细粒的代码控制配合惰性加载事件处理程序以及事件委托来缩短首屏。

这样LCP, FDI指标 是不是完美实现了?

qwik其实并不是因为使用了多么牛逼的算法导致它有多么快,而它的速度正是得益于它的设计思路,省略了传统 SSR 下首屏需要加载庞大的 JS进行 hydration 的过程。

Next.js

Next.js【Vercel 是由 Guillermo Rauch 创立的云服务公司】有很大的商业利益驱动

云服务开发商嗅到了商机 开发了 Next.js (名字起的就很噱头)

  • 开发一个框架 能 完美的满足Google的指标,为用户提供一站式的门户站点。

  • 应该有丰富的生态,最好能复用React的完善生态。

Next.js是一个React框架,它允许你使用React框架建立超强的、有利于SEO的、极度面向用户的静态网站和网络应用。Next.js以在构建具有你所需要的所有功能的生产就绪的应用程序时的最佳开发者体验而闻名。

Next.js得到了财富500强企业的支持,包括GitHub、Uber和Netflix。 包括TikTok

预建SSR、ISR、SSG和CSR

Next.js的巨大功能之一是预渲染,它使Next.js工作得非常好、非常快。Next.js通过预先生成每个页面的HTML和它们需要运行的最小的JavaScript,通过一个被称为Hydration的过程来预渲染每个页面。

Next.js的预渲染有两种形式:

  • 服务器端渲染 (SSR)
  • 静态生成(SSG)

如何获取数据是SSG和SSR的关键区别。对于SG来说,数据是在构建时获取的,并在每次请求中重复使用(这使得它更快,因为它可以被缓存),而在SSR中,数据是在每次请求中获取的。

Next.js 核心实现

Next.js 自研了一个全栈框架,从开发到部署做到了闭环。从商业角度看把易用性放在核心位置是合理的,后边发展的思路应该是

OK我们接着聊一下Next.js的一些核心特性:

如何实现SSG的?

// pages/posts/[id].js 官方的🌰
function Post({ post }) {
  // Render post...
}
export async function getStaticPaths() { // getStaicPaths是当前的path,直接结果会传入getStaticProps中
  // ...
}
// 在构建时也会被调用
export async function getStaticProps({ params }) { // 生成组件参数,生成静态文件
  // params 包含此片博文的 `id` 信息。
  // 如果路由是 /posts/1,那么 params.id 就是 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()
  // 通过 props 参数向页面传递博文的数据
  return { props: { post } }
}
export default Post

在编译阶段(next build) 框架会找pages页面作为路由入口,如果文件中包含了 getStaticProps 方法就会默认为此方法为静态生成。 然后执行 getStaticPaths 和 getStaticPaths 会获得组件生成所需要的参数 进行生成静态资源。

如何实现SSR?

要对 page(页面)使用服务器端渲染,你需要 export 一个名为 getServerSideProps 的 async 函数。服务器将在每次页面请求时调用此函数。

这块不多阐述

处于商业化如何提升指标的?

  • 使用静态生成,如果没有hook的,在编译可以直接优化为静态页面(SSG), 有hook的在服务端也可以进行SSR,惊艳的SSR / SSG 手段,但是依然需要水合, 并且有利于SEO操作。

  • Next/image, 在build阶段对图片进行处理,并且支持懒加载,以及占位符。

  • Next/link, 如果在视图内会提前的请求渲染下一个页面所需的 JSON文件。

  • 字体优化,By default, Next.js will automatically inline font CSS at build time, eliminating an extra round trip to fetch font declarations. This results in improvements to First Contentful Paint (FCP) and Largest Contentful Paint (LCP).

  • 甚至提供了后端服务直接写api的功能,甚至提供了编写中间件能力。

Next.js试图再为开发者提供全栈的解决方案,开发者通过较低成本可以完成前后端高性能的站点建设。主要适用的场景是 营销页面、博客文章、电子商务产品列表、帮助和文档。

Island(Astro)

这是一种架构,一种思想。

Astro

这是一套基于SSR(服务端渲染)的实现方法,从传统的SSR的缺陷说起。

在传统SSR中,首屏渲染时,服务端会向浏览器输出HTML结构。

当浏览器渲染HTML后,再执行前端框架的初始化逻辑,为HTML结构绑定事件,这一步叫hydrate(注水)。

当hydrate完成后,页面才能响应用户交互。

也就是说,只有当整个页面所有组件hydrate完成后,页面中任一组件才能响应用户交互。

如果说Qwik框架也满足 island也没问题。

对于Astro,孤岛架构适用的对象是组件。而在Qwik中,孤岛架构最细的粒度是组件中的某个方法。

也就是说,开发者可以在Astro中使用React、Vue、Preact、Svelte等框架实现具体业务逻辑,甚至是在一个.astro组件中混用其他框架的组件。

怎么实现的?
Astro 对于多种前端框架的支持是通过一种名为 "组件编译器" 的工具实现的。这个工具会将各种前端框架的组件转换为 Astro 的内部表示形式,这样这些组件就可以在 Astro 的环境中被使用和渲染。

当开发者在 Astro 中使用一个特定的框架的组件时,Astro 的组件编译器会将这个组件转换为 Astro 的组件格式,并将它与 Astro 的其他组件一起编译和打包。这样,即使应用程序中同时使用多种框架,Astro 也能够处理它们,并将它们整合到一个统一的应用程序中。

像不像微前端框架? 岛屿之间互相独立,可以独立加载和交互, 相比 SPA,岛屿架构在以内容为中心的场景下,优势也非常明显。

以使用纯 HTML 和 CSS 为所有静态内容创建 Web 应用程序,然后添加动态内容或交互区域(孤岛),这些区域可以使用框架来添加交互性,并且这些区域可以使用任何框架,运行态框架只有在使用到它的页面上才会被下载,而不是在网站的初始加载中。

Astro 和 NextJs 的区别

Astro 和 Next.js 都是用于构建 Web 应用程序的框架,但它们有一些不同点。

  • 架构模式区别:Astro 和 Next.js 的架构模式不同。Astro 基于组件编译器构建,使用标准的 Web 技术(如 JavaScript、CSS 和 HTML)构建应用程序。而 Next.js 是一个服务器渲染(SSR)框架,将服务器端和客户端渲染相结合,通过内置的路由和 API 管理器来管理应用程序的生命周期。

  • 框架支持区别:Astro 支持多种前端框架,包括 React、Vue 和 Svelte 等。而 Next.js 主要基于 React,但也支持 Vue 和 Angular 等其他前端框架。

  • 构建方式区别:Astro 使用 Snowpack 构建工具,可以快速地构建应用程序,而 Next.js 使用 webpack 构建工具进行应用程序打包和优化。

  • 配置方式区别:Astro 的配置方式更加简单和直观,只需要一个简单的 Astro 配置文件即可。而 Next.js 则有更多的配置选项,并且需要开发人员更深入地了解它的配置文件。

  • 性能方面区别:Astro 在许多方面都注重性能,如服务端渲染、自动代码分割和图像优化等。Next.js 也有类似的性能优化,但它的优化方法可能略有不同。

相关参考: 岛屿架构

按照前端架构维度来介绍技术文章

关于我
loading