百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Astro 2.x大火!深入混合渲染原理与5+新特性!

bigegpt 2024-08-18 14:09 2 浏览

家好,很高兴又见面了,我是"高级前端?进阶?",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

1.什么是 Astro

Astro 是一种流行的 Web 框架,用于构建以内容为中心的高性能网站。Astro 代表下一代前端架构,可以优化网站,允许选择已有的 UI 框架(如 React、Svelte 和 Vue),使用 Astro 构建的站点加载速度提高 33%,JavaScript 大小减少 90%。

但是,自 Astro 1.0 首发以来,开发人员不得不在 SSG 或 SSR 之间做出选择。 SSG 通过提前构建页面来提升性能,而 SSR 利用动态能力按需生成 HTML。但是,随着 Astro 2.0 的发布,其通过混合渲染实现了 SSG、SSR 的两全其美。

Astro 2.0 是第一个为 Markdown 和 MDX 提供完整类型安全的 Web 框架。 Astro 可以通过内置的解析、验证和自动 TypeScript 类型生成来组织 Markdown。 对于在站点上使用 Markdown 来说,Astro 2.0 的发布是一个很好的消息。

Astro 2.0 的新特性还包括:Markdown 和 MDX 的自动类型安全检测、混合渲染(静态&动态结合)、重新设计错误(引入错误叠加层(Error Overlay))、开发服务器优化、集成 Vite 4.0 等等。

Astro 在 2 年前开源,在 Github 上有超过 28.4K 的 star,1.4k 的 fork,有超过 29.2k 的项目使用它,NPM 周平均下载量超过 84K。而本文将重点探索 Astro 2.0 中的混合渲染的工作原理。

2.Astro 的构建过程

Astro 的构建过程分多个阶段进行,从 Vite 生成的服务器端 JavaScript 包开始。 输出的包内容包括:

  • 用于渲染 HTML 的服务器端 JavaScript
  • 使用静态分析收集客户端交互所需的所有组件的客户端清单(client manifest)
  • 客户的 CSS 和其他资源

接下来,Astro 使用客户端清单启动第二个构建过程,该过程打包优化的客户端 JavaScript。如果开发者配置的 output 是 static,Astro 将执行服务器端 JavaScript 并将输出写入 .html 文件, 然后丢弃服务器端 JavaScript。

如果配置的 output 是 server,则 Astro 将服务器端 JavaScript 传递给适配器以进行进一步处理。 适配器确保服务器端 JavaScript 与特定托管服务提供商的 JavaScript 运行时兼容。 请注意,在这种情况下,最终输出不是一组 .html 文件,而是渲染 HTML 所需的 JavaScript 代码。

不幸的是,这种设置非常严格,不允许在同一个项目中混合使用静态和动态路由,而这正是 Astro 2.0 所需要的。

3.Astro 2.0 混合渲染

Astro 2.0 改进了 astro 构建管道以处理混合渲染。 在最初的打包过程中,一个新的静态分析步骤决定了哪些页面应该被预渲染。 这允许开发者将路由(routes)分成单独的块,具体取决于何时渲染。

SSG:与以前的 static 过程非常相似,执行预渲染块并将输出写入 .html 文件, 然后丢弃这些块。

SSR:与以前的 server 过程非常相似,服务器块被传递给适配器以进行进一步处理。 它最终将部署为无服务器或边缘函数,具体取决于适配器。

4.静态分析

4.1 es-module-lexer

es-module-lexer 是 es-module-shims 中使用的 JS 模块语法词法分析器。是一个非常小的单个 JS 文件,压缩后为 4K,其包含内联 WebAssembly,仅用于对 ECMAScript 模块语法进行非常快速的源代码分析。

es-module-lexer 输出的是 export 列表和 import 说明符的位置,包括动态导入(Dynamic Import)和导入元(Import Meta)处理。

举个性能的例子:es-module-lexer 对 720K 的 Angular 1 文件 可以在 5 毫秒内完成解析,而最快的 JS 解析器 Acorn 则需要 100 多毫秒。接下来要说的 Astro 静态分析技术就是在 es-module-lexer 的 基础上完成的。

4.2 Astro 的静态分析

静态分析是一种用于分析源代码而不实际执行的技术, Astro 在很多地方都依赖于这种方法,在构建过程中尤为重要。 出于性能原因,Astro 必须能够在不执行其源代码的情况下对页面进行分类。 对于体积较小的项目,执行可能不是问题,但随着站点规模的扩大执行就会成为瓶颈。

混合渲染是专门为静态分析而设计的,Astro 的构建过程能够检查是否存在 export const prerender = true 语句以确定应预渲染哪些页面。 为了高效地做到这一点,Astro 借助于出色的 es-module-lexer 库,这个库也在 Node.js 内部使用。

---
// 这个路由应该在构建时预渲染
export const prerender = true

const text = await fetch("https://example.com/").then((res) => res.text())
---

<article set:html={text} />

5.混合渲染场景

5.1 用例:提高流行页面的渲染性能

考虑一个使用 Astro 构建的小、中型电子商务网站,包含数千种不同的产品。 如果要使用静态站点生成 SSG,那么任何一个产品发生变化或缺货时,将不得不重新构建整个网站。

此时就需要服务端渲染,即允许产品页面根据每个请求动态生成。 这又引入了一个新问题,即主页也不再是静态渲染的。而加载性能对于销售量至关重要,同时主页没有任何动态内容需要根据每个请求重新构建。

混合渲染通过提前将主页渲染为静态 HTML 来解决此性能问题,同时保持站点的其余部分按需渲染。

5.2 将 API 添加到现有的静态站点

随着静态网站的增长,可能会发现需要托管一个公共 API。 从历史上看,向静态站点添加 API 需要特定于机器的配置,但在 Astro 2.0 中,可以在不牺牲静态页面性能的情况下添加服务器端点(API 路由)。

import type { FunctionalComponent } from 'preact';
import { h } from 'preact';
// 下面需要通过fetch请求数据
const data = await fetch('https://example.com/movies.json').then((response) =>
  response.json()
);

console.log(data);

const Movies: FunctionalComponent = () => {
  return <div>{JSON.stringify(data)}</div>;
};

export default Movies;

事实上,服务器端点可以通过 Integrations API 的 injectRoute hooks 自动添加,从而快速实现与强大的第三方生态系统集成!

injectRoute({
  pattern: '/foo/[dynamic]',
  entryPoint: 'foo/dynamic-page.astro',
});

5.3 用例:提高大型站点的构建性能

静态生成 SSG 很难扩展到数千个页面,因为每个页面都必须在构建过程中渲染。 服务端渲染将页面渲染推迟到请求时,从而消除构建过程中的潜在瓶颈。

当 getStaticPaths 生成数百条路由时,服务器端渲染可以带来显著的性能提升。 在内部测试中,通过将动态路由切换到服务器端渲染,发现构建时间最多缩短了 30%。

6.Astro 2.1 新特性

2023 年 3 月 8 日, Astro 2.1 发布,又新增了以下诸多特性:

6.1 内置图像支持

Astro 2.1 为 Astro 带来了对内置图像优化的实验性支持。 要在项目中启用它,可以使用 --experimental-assets 标志运行 Astro 或在 Astro 配置文件中设置 experimental.assets 布尔标志。

如果已经熟悉 @astrojs/image 集成,Astro 的新内置 <Image> 组件应该感觉很熟悉,但有一些显著的改进。 现在可以使用 width 和 height 属性调整图像的大小而不改变其纵横比,并使用新的 quality 属性控制图像优化级别。

---
import { Image } from "astro:assets"
import penguin from "~/assets/penguin.png"
---

<Image src={penguin} quality="high" alt="a high-quality penguin" />

生成的图像将以现代网络格式自动优化,以最小的累积布局偏移 (CLS) 实现最佳性能。

6.2 集成 Markdoc

一个新的实验性 Markdoc 集成也与 Astro 2.1 一起发布。 现在可以通过在项目目录中运行 npx astro add markdoc 来将 @astrojs/markdoc 添加到项目中。

Markdoc 是 Stripe 在需要适合其规模的东西时开发的一种很有前途的新内容格式。 虽然仍然喜欢 Astro 的 MDX,但用户在处理大量 MDX 文件时发现速度明显下降的情况并不少见。

Astro 建立了一个性能基准来比较 Astro 内部的 Markdoc 构建性能与现有的内容格式:Markdown 和 MDX,惊奇的发现构建速度比 MDX 渲染静态内容和可交互岛屿快了 3 倍。

一旦将 @astrojs/markdoc 集成添加到项目中,Markdoc 就可以使用 .mdoc 文件扩展名在内容集合中使用。 可以将 Markdoc 文件与现有的 Markdown 和 MDX 文件混合使用,以实现平稳、渐进的迁移过程。

6.3 astro check

astro check 是一个内置的 Astro CLI 命令,可以对项目的 .astro 文件运行 TypeScript 类型检查。 它通常用于在合并更改或部署站点之前捕获 CI 中的错误和类型错误。

{
	"scripts": {
		"dev": "astro check --watch & astro dev"
	}
}

在 Astro 2.1 中,一个新的 --watch 标记已添加到 astro 检查命令中。 这将产生一个长时间运行的进程,用于侦听文件更改并对更改的文件重新运行诊断。 可以通过将脚本添加到 package.json 来与开发服务器并行运行它。

6.4 动态路由的推断类型

Astro 页面中的 getStaticPaths() 导出用于定义应为 SSG 模式下的动态路由构建哪些页面。 对于每个页面,返回一个 params 和 props 属性。

在 Astro 2.1 中,添加了两个新的 helper 来推断这些类型,并在模板中使用这些值时提供类型检查。

给定以下 getStaticPaths() 函数:

---
// Example: src/pages/blog/[slug].astro
export async function getStaticPaths() {
	const posts = await getCollection("blog")
	return posts.map((post) => {
		return {
			params: { slug: post.slug },
			props: { draft: post.data.draft, title: post.data.title },
		}
	})
}
---

现在可以使用新的 InferGetStaticParamsType 和 InferGetStaticPropsType 来获取参数和 props 值的类型定义,而无需手动定义它们:

import { InferGetStaticParamsType, InferGetStaticPropsType } from 'astro';
export async function getStaticPaths() {
  /* ... */
}

type Params = InferGetStaticParamsType<typeof getStaticPaths>;
type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const { slug } = Astro.params;
//               ^? { slug: string; }
const { title } = Astro.props;
//                ^? { draft: boolean; title: string; }

7.本文总结

本文主要和大家介绍Astro 2.x,文章从什么是 Astro、Astro 的构建过程、Astro 2.0 混合渲染原理、混合渲染适用场景、Astro 2.1 新特性等诸多维度展开。

因为篇幅有限,文章并没有过多展开,如果有兴趣,可以在我的主页继续阅读,同时文末的参考资料提供了大量优秀文档以供学习。最后,欢迎大家点赞、评论、转发、收藏!

参考资料

https://astro.build/blog/hybrid-rendering/

https://astro.build/blog/astro-2/

https://astro.build/blog/introducing-content-collections/

https://vitejs.dev/blog/announcing-vite4.html

https://astro.build/

https://docs.astro.build/en/guides/markdown-content/

https://github.com/withastro/astro

https://astro.build/blog/astro-210/

相关推荐

悠悠万事,吃饭为大(悠悠万事吃饭为大,什么意思)

新媒体编辑:杜岷赵蕾初审:程秀娟审核:汤小俊审签:周星...

高铁扒门事件升级版!婚宴上‘冲喜’老人团:我们抢的是社会资源

凌晨两点改方案时,突然收到婚庆团队发来的视频——胶东某酒店宴会厅,三个穿大红棉袄的中年妇女跟敢死队似的往前冲,眼瞅着就要扑到新娘的高额钻石项链上。要不是门口小伙及时阻拦,这婚礼造型团队熬了三个月的方案...

微服务架构实战:商家管理后台与sso设计,SSO客户端设计

SSO客户端设计下面通过模块merchant-security对SSO客户端安全认证部分的实现进行封装,以便各个接入SSO的客户端应用进行引用。安全认证的项目管理配置SSO客户端安全认证的项目管理使...

还在为 Spring Boot 配置类加载机制困惑?一文为你彻底解惑

在当今微服务架构盛行、项目复杂度不断攀升的开发环境下,SpringBoot作为Java后端开发的主流框架,无疑是我们手中的得力武器。然而,当我们在享受其自动配置带来的便捷时,是否曾被配置类加载...

Seata源码—6.Seata AT模式的数据源代理二

大纲1.Seata的Resource资源接口源码2.Seata数据源连接池代理的实现源码3.Client向Server发起注册RM的源码4.Client向Server注册RM时的交互源码5.数据源连接...

30分钟了解K8S(30分钟了解微积分)

微服务演进方向o面向分布式设计(Distribution):容器、微服务、API驱动的开发;o面向配置设计(Configuration):一个镜像,多个环境配置;o面向韧性设计(Resista...

SpringBoot条件化配置(@Conditional)全面解析与实战指南

一、条件化配置基础概念1.1什么是条件化配置条件化配置是Spring框架提供的一种基于特定条件来决定是否注册Bean或加载配置的机制。在SpringBoot中,这一机制通过@Conditional...

一招解决所有依赖冲突(克服依赖)

背景介绍最近遇到了这样一个问题,我们有一个jar包common-tool,作为基础工具包,被各个项目在引用。突然某一天发现日志很多报错。一看是NoSuchMethodError,意思是Dis...

你读过Mybatis的源码?说说它用到了几种设计模式

学习设计模式时,很多人都有类似的困扰——明明概念背得滚瓜烂熟,一到写代码就完全想不起来怎么用。就像学了一堆游泳技巧,却从没下过水实践,很难真正掌握。其实理解一个知识点,就像看立体模型,单角度观察总...

golang对接阿里云私有Bucket上传图片、授权访问图片

1、为什么要设置私有bucket公共读写:互联网上任何用户都可以对该Bucket内的文件进行访问,并且向该Bucket写入数据。这有可能造成您数据的外泄以及费用激增,若被人恶意写入违法信息还可...

spring中的资源的加载(spring加载原理)

最近在网上看到有人问@ContextConfiguration("classpath:/bean.xml")中除了classpath这种还有其他的写法么,看他的意思是想从本地文件...

Android资源使用(android资源文件)

Android资源管理机制在Android的开发中,需要使用到各式各样的资源,这些资源往往是一些静态资源,比如位图,颜色,布局定义,用户界面使用到的字符串,动画等。这些资源统统放在项目的res/独立子...

如何深度理解mybatis?(如何深度理解康乐服务质量管理的5个维度)

深度自定义mybatis回顾mybatis的操作的核心步骤编写核心类SqlSessionFacotryBuild进行解析配置文件深度分析解析SqlSessionFacotryBuild干的核心工作编写...

@Autowired与@Resource原理知识点详解

springIOCAOP的不多做赘述了,说下IOC:SpringIOC解决的是对象管理和对象依赖的问题,IOC容器可以理解为一个对象工厂,我们都把该对象交给工厂,工厂管理这些对象的创建以及依赖关系...

java的redis连接工具篇(java redis client)

在Java里,有不少用于连接Redis的工具,下面为你介绍一些主流的工具及其特点:JedisJedis是Redis官方推荐的Java连接工具,它提供了全面的Redis命令支持,且...