jiechenjiechen

The world is quiet here.

© jiechen

Rebuild in 2023   |   Start in 2021
Total View 0 Site Visitors 0

新兴的Astro

2023年4月23日front-end2180 字约 15 分钟

Astro

框架定位

先来聊一聊 Astro 框架的定位,是像 Vue、React 这样的底层渲染框架,还是像 Next.js 这种上层的研发框架?

这一点其实挺困扰初学者的,因为 Astro 既自创了类似于.vue.jsx文件的 .astro 语法,又提供了像 Next.js 里面各种运行时的能力,比如约定式路由、构建优化、SSR 等等。

但实际上它给自己的定位非常清晰,即 content-focused 应用开发框架,换句话说,就是重内容、轻交互场景下的上层研发框架,比如大多数电商网站、文档站、博客站、证券网站等等。

你可以将 Astro 理解为一个垂直场景下的Next.js,但它可以在它适用的领域里面可以胜过其它所有竞品(如Next.jsRemixVuepress 等),这是它能够做起来的重要原因。接下来,我们就来看看 Astro 的优势在于哪些地方。

核心优势

Astro 的主要优势包括如下几点:

  • Islands 架构,解决传统 SSR/SSG 框架的全量 hydration 问题,做到尽可能少的 Client 端 JS 的开销,甚至是 0 JS。
  • 学习成本低。.astro 语法和传统的 .jsx.vue 非常相似,对于新手前端来说也比较容易掌握。
  • 使用灵活。对于页面的开发,你既可以使用官方的.astro 语法,也同样可以使用 .md.vue.jsx 语法,也就是说,你可以自由选择其它前端框架的语法来开发,甚至可以在一个项目中同时写 Vue 组件和 React 组件!
  • 构建迅速。底层构建体系基于 Vite 以及 Esbuild 实现,项目启动速度非常快。

Islands 架构

在如上的几个优点中,我们来重点说一说 Astro 的 Islands 架构,因为这是它高性能最主要的原因。

Islands 架构模型早在 2019 年就被提出来了,并在 2021 年被 Preact 作者Json MillerIslnads Architecture 一文中得到推广。这个模型主要用于 SSR (也包括 SSG) 应用,我们知道,在传统的 SSR 应用中,服务端会给浏览器响应完整的 HTML 内容,并在 HTML 中注入一段完整的 JS 脚本用于完成事件的绑定,也就是完成 hydration (注水) 的过程。当注水的过程完成之后,页面也才能真正地能够进行交互。

那么当应用的体积逐渐增大时,需要在客户端执行的 JS 脚本也会越来越多,这也意味着 TTI(可交互时间) 指标越来越高:

为了解决这个问题,Islands 架构将页面拆分为各自独立的组件,包含静态组件可交互组件,如下图的例子所示:

可以清楚的看到,一个页面中只有部分的组件交互,那么对于这些可交互的组件,我们可以并行地执行 hydration 过程,因为组件之间是互相独立的。

而对于静态组件,即不可交互的组件,我们可以让其不参与 hydration 过程,直接复用服务端下发的 HTML 内容。

可交互的组件就犹如整个页面中的孤岛(Island),因此这种模式叫做 Islands 架构:

相比于传统 SSR 中的全量 hydration,Islands 模式可以实现局部(partial) hydration,从而优化 JS 的体积,减少网络传输的成本和 JS 运行时的开销。

在 Astro 中,默认所有的组件都是静态组件,比如:

1
2
3
4
// index.astro
import MyReactComponent from '../components/MyReactComponent.jsx';
---
<MyReactComponent />

值得注意的是,这种写法不会在浏览器添加任何的 JS 代码。但有时我们需要在组件中绑定一些交互事件,那么这时就需要激活孤岛组件了,在 Astro 如何来激活呢?其实很简单,在使用组件时加上client:load指令即可:

1
2
3
4
5
// index.astro
---
import MyReactComponent from '../components/MyReactComponent.jsx';
---
<MyReactComponent client:load />

如此一来,Astro 会给浏览器传输一部分 JS 代码供这个组件完成 hydration,以便后续的交互。

Astro 2.0

  • 内容集合:Markdown 和 MDX 的自动类型安全;
  • 混合渲染:支持静态渲染和动态渲染;
  • 重新设计的错误 Overlays;
  • 改进的开发服务器 (HMR);
  • Vite 4.0;
  • 新的公开路线图

详情参考:Astro 2.0正式发布,现代化静态站点生成器 - 掘金

SSR和SSG

1. 静态资源和动态资源分别是什么?

首先静态资源和动态资源都是服务端这边的概念,因为我们访问互联网本质都是访问对应的服务端

对于服务端来说:

  • 静态资源是:提前准备好的,写死了的,直接文件IO就可以response的属于静态资源。
  • 动态资源是:不是写死的,需要读库的 或 需要调下游接口的 或 需要脚本处理的属于动态资源

前端角度看哪些是静态资源?

  1. 通过前端工程npm run build编译好的js、css、html文件,都属于静态资源
  2. 提前准备好的文件(比如自己开发的源代码),都属于静态资源
  3. 图片、视频等资源文件,都属于静态资源

前端角度看哪些是动态资源?

  1. 需要调接口才能得到的内容,并且内容不是提前准备好的,属于动态资源

2. 从架构角度看动、静态资源

1. 请求SSR架构的服务的html属于静态资源还是动态资源?

结论:属于动态资源

因为:html没有提前准备好,没有提前静态化。是来一个请求,就动态编译生成html的

2. 请求SSG架构的服务的html属于静态资源还是动态资源?

结论:属于静态资源

因为:html被提前静态化了。无需实时编译

3. 引发对性能优化的思考

SSR架构的存在问题,以及如何解决

SSR架构性能好是最大的特色之一,但被人诟病的一个最大问题也是性能问题,原因:

  • SSR架构的性能好,其实是针对前端来说的

    • 对于前端用户来说,访问SSR的服务,可以直接得到完整的html(CSR架构的html是空的,没有dom内容,dom内容需等js后续生成的),

    • 并且如果你的首屏需要被多个接口阻塞时,SSR可以在服务端把请求处理完

    • 服务端处理请求非常非常快,举个栗子:同一个接口前端ajax需要1s,服务端请求可能只需20ms,因为服务端可以抹掉网络连接的阻塞,可能和目标下游服务器就在同一个机房

  • SSR架构对于服务端来说,性能非常差

    • 这个怎么理解呢? 其实是和服务端接口来做对比的,比如接口的QPS可以很容易超过1000,但SSR的处理QPS可能只有10,因为html是动态生成的,需要大量的时间来编译得到html,所以对于接口来说,SSR的性能很差很差
  • 解决办法

    • 做成SSG(静态化

      • 原理:提前编译好html,节省编译html的时间,让 请求动态资源 变成 请求静态资源。

      • 但也不是没副作用的,副作用是:会丢失动态化能力,比如我本来可以在服务端根据用户的ip,显示对应的语言的html。做成SSG之后,只能默认显示一种语言。并且也无法在服务端把阻塞请求处理完

    • 不过有办法可以解决上面SSG架构的缺陷(动静结合!

      • 原理:在多加一层bff层,由这一层来处理动态化部分

      • 比如 把阻塞请求处理完,通过{{ }}占位标识,替换掉对应html内的数据。

      • 比如 根据用户ip显示多语言的问题,需要我们提前用ssg编译好多份html(对应多语言),然后由bff来处理。。(确实做的有点复杂了,不过假如要追求极致性能的话,这是一种选择)

参考

Astro 1.0 正式发布,给前端带来了什么

对静态资源和动态资源的思考,延伸至SSR和SSG的性能优化