就在上周,Astro 团队发布了 1.0 的正式版本。
从年初我就开始关注这个项目了,但当时只是学习了一下仓库的工程化搭建相关的东西 (changesets 自动发包之类),并没有深入了解它本身的功能。借着正式发版的机会,这几天熟悉了一下 Astro 1.0,发现了很多有意思的地方,下文会分别从团队背景、框架定位和核心优势几个维度给大家展开介绍,最后也会推荐一些学习资料。
在正式介绍 Astro 之前,先给大家聊一聊相关的背景。Astro 的作者是 Fred K. Schott
,没错,就是那个开发 Snowpack 的老哥,可以说是 Unbundle 构建工具的祖师爷:
但无奈的是 Vite 发展势头实在太猛,而 Snowpack 渐渐日薄西山,他本人也写了文章发出下面的感慨:
文章链接: https://dev.to/fredkschott/5-more-things-i-learned-building-snowpack-to-20-000-stars-5dc9
大意就是 Snowpack 前途渺茫,用户越来越少,感觉要做到头了啦,而 Vite 发展的非常好,那后面开发的 Astro 就基于 Vite 来做吧。现在连 Snowpack 的官网都表示弃坑了,主动给 Vite 引流:
当然,除了 Snowpack,Fred K. Schott
的团队(叫Pika
)还做了一件比较知名的产品: Skypack
,即 NPM 包的 ESM CDN 服务:
不幸的是,Skypack 也很长时间(一年多)没有维护了,可以看出团队也不再想继续投入这个项目了,个人感觉主要有两个原因:
在近些年的时间里,Fred K. Schott
团队一直将重心放在了新项目 Astro 上面,经过 16 个月的打磨, Astro 在全球拥有了 30000 多个用户,被 Google、Netlify 等大公司使用,Github 的 star 已经达到 15k +。
值得一提的是,Fred K. Schott
为了这个项目专门成立了一个创业公司: The Astro Technology Company
,并且已经融到了 700 万美刀
的种子轮投资,打算一直以开源的方式发展下去。相比于一些知名开源项目的赞助收入,如 Webpack[1] 22 w 刀/年、Babel[2] 30 w 刀/年,Astro 在经济方面有如鱼得水的优势。
接下来聊一聊 Astro 框架的定位,是像 Vue、React 这样的底层渲染框架,还是像 Next.js 这种上层的研发框架?
这一点其实挺困扰初学者的,因为 Astro 既自创了类似于.vue
、.jsx
文件的 .astro
语法,又提供了像 Next.js 里面各种运行时的能力,比如约定式路由、构建优化、SSR 等等。
但实际上它给自己的定位非常清晰,即 content-focused
应用开发框架,换句话说,就是重内容、轻交互场景下的上层研发框架,比如大多数电商网站、文档站、博客站、证券网站等等。
你可以将 Astro 理解为一个垂直场景下的Next.js
,但它可以在它适用的领域里面可以胜过其它所有竞品(如Next.js
、Remix
、Vuepress
等),这是它能够做起来的重要原因。接下来,我们就来看看 Astro 的优势在于哪些地方。
Astro 的主要优势包括如下几点:
.astro
语法和传统的 .jsx
和 .vue
非常相似,对于新手前端来说也比较容易掌握。.astro
语法,也同样可以使用 .md
、.vue
、.jsx
语法,也就是说,你可以自由选择其它前端框架的语法来开发,甚至可以在一个项目中同时写 Vue 组件和 React 组件!在如上的几个优点中,我们来重点说一说 Astro 的 Islands 架构,因为这是它高性能最主要的原因。
Islands 架构模型早在 2019 年就被提出来了,并在 2011 年被 Preact 作者Json Miller
在Islnads Architecture[3] 一文中得到推广。这个模型主要用于 SSR (也包括 SSG) 应用,我们知道,在传统的 SSR 应用中,服务端会给浏览器响应完整的 HTML 内容,并在 HTML 中注入一段完整的 JS 脚本用于完成事件的绑定,也就是完成 hydration (注水) 的过程。当注水的过程完成之后,页面也才能真正地能够进行交互。
那么当应用的体积逐渐增大时,需要在客户端执行的 JS 脚本也会越来越多,这也意味着 TTI(可交互时间) 指标越来越高:
为了解决这个问题,Islands 架构将页面拆分为各自独立的组件,包含静态组件
和可交互组件
,如下图的例子所示:
可以清楚的看到,一个页面中只有部分的组件交互,那么对于这些可交互的组件,我们可以并行地执行 hydration 过程,因为组件之间是互相独立的。
而对于静态组件,即不可交互的组件,我们可以让其不参与 hydration 过程,直接复用服务端下发的 HTML 内容。
可交互的组件就犹如整个页面中的孤岛(Island),因此这种模式叫做 Islands 架构:
相比于传统 SSR 中的全量 hydration,Islands 模式可以实现局部(partial) hydration,从而优化 JS 的体积,减少网络传输的成本和 JS 运行时的开销。
在 Astro 中,默认所有的组件都是静态组件,比如:
// index.astro
import MyReactComponent from '../components/MyReactComponent.jsx';
---
<MyReactComponent />
值得注意的是,这种写法不会在浏览器添加任何的 JS 代码。但有时我们需要在组件中绑定一些交互事件,那么这时就需要激活孤岛组件
了,在 Astro 如何来激活呢?其实很简单,在使用组件时加上client:load
指令即可:
// index.astro
---
import MyReactComponent from '../components/MyReactComponent.jsx';
---
<MyReactComponent client:load />
如此一来,Astro 会给浏览器传输一部分 JS 代码供这个组件完成 hydration,以便后续的交互。
读到这里,你可能会说了,相比于其它的业界方案,Astro 到底优势在哪里呢?我们不妨来盘点一下。
首先是大名鼎鼎的 Next.js,我们知道 Next.js 是一个非常经典的 React SSR 框架,也是使用传统的 SSR/SSG 技术,可以适用于几乎所有的 Web 开发场景。而 Astro 在其适用的content-focused
场景下,性能会明显高于 Next.js,以下是两个真实的迁移案例:
可以看到,Astro 相比 Next.js 可以大幅度减少 JS 代码的体积(90% 以上),同时页面的运行时性能也提升了 30% 以上。除此之外,Astro 不仅支持使用 React 框架,而且支持 Vue、Solid 等在内的各种前端框架,灵活性更高。
其次是最近比较火的新秀框架 Remix
,它基于 react-router 管理组件,通过 loader 和 action 的概念尽可能将逻辑代码放到服务端的 bundle,从而减少客户端 JS 的代码体积,同样是崇尚 0 JS 的理念,Remix 却仍然需要全量 hydration,无法完成 partial hydration。此外,Astro 还有两大优势:
React 18 提供了 renderToPipeableStream
API,真正实现了 SSR 场景下的 Selection Hydration
,主要有如下的几个特点:
如果用户在这个过程中点击了 Comment 组件,那么 React 会中断当前对于 SideBar 组件的 hydrate,从而去执行 Comment 组件的 hydrate:
详情可见 React 18 SSR Architecture: https://github.com/reactwg/react-18/discussions/37
那么 Astro 中的 Islands 架构,即 Partial Hydration
,和 React 的 Selection Hydration
到底是不是一个东西呢?
答案是否定的。两者存在着非常大的区别:
Selection Hydration
依附于具体框架的实现,而 Partial Hydration
可以做到框架无关,即使是 Vue、Solid 的项目也可以做到 Partial Hydration
。Partial Hydration
可以做到加载部分组件的 JS 代码,而 Selection Hydration
仍然需要加载和执行全量的 JS 代码。Selection Hydration
严重依赖于流式(Streaming)渲染,服务端需要加上 transfer-encoding: chunked
的响应头,而 Partial Hydration
没有这个限制。因此,虽然两者都是在 Hydration 上做文章,但其实是两种完全不同的方案,而且 Partial Hydration
更加通用,限制更少,执行的 JS 更少。
以上就是对 Astro 的介绍和分析,后面有机会给大家剖析一下内部的源码实现。文中如有不妥的地方,欢迎大家评论和指正。最后给大家推荐一些 Astro 的学习资料,方便大家读完文章进一步了解:
[1]
Webpack: https://opencollective.com/webpack
[2]
Babel: https://opencollective.com/babel
[3]
Islnads Architecture: https://jasonformat.com/islands-architecture/