专栏名称: 前端早读课
我们关注前端,产品体验设计,更关注前端同行的成长。 每天清晨五点早读,四万+同行相伴成长。
目录
相关文章推荐
前端早读课  ·  【早阅】使用Node.js中的内置SQLite模块 ·  昨天  
前端早读课  ·  【图书】HarmonyOS ... ·  3 天前  
前端早读课  ·  【早阅】Deno 2.0 发布:七大核心更新亮点 ·  5 天前  
前端大全  ·  Rust编写的跨平台UI框架——Tauri正 ... ·  6 天前  
前端早读课  ·  【第3390期】如何在用户界面中管理危险操作 ·  6 天前  
51好读  ›  专栏  ›  前端早读课

【第3392期】前端框架Astro在房产业务实践

前端早读课  · 公众号  · 前端  · 2024-10-15 08:00

正文

前言

介绍了热门前端框架 Astro 在房产业务中的实践应用,包括 Astro 的特性、性能优势、项目实践案例以及如何解决在实践中遇到的问题。今日前端早读课文章由 @张志鹏分享,公号:58 技术授权。

正文从这开始~~

Astro 介绍

为什么使用 Astro

随着业务不断地发展,对项目的要求也越来越高。加载要更快,性能要更好,资源消耗要更少,同时也要减少开发成本,并且还要满足业务的各种诉求。经过我们的调研最终我们锁定了 Astro 框架,Astro 具有轻量级与高性能、卓越的 SEO 优化、兼容性与灵活性、简洁的开发体验、出色的社区支持、成本效益高等优势。能一站式解决了我们大部分诉求。

什么是 Astro

Astro 是一个现代化的静态站点生成器和前端框架。Astro 由原 Snowpack 团队于 21 年 4 月创建,并于 22 年 8 月发布了 1.0 正式版本,当前已经发布到了 4.x 版本。从创建至今的 3 年时间里,Astro 的 Star 数已经达到 46k。对比创建 3 年时的 Vue Star 数是 26k、React Star 数是 37k。从下图可以看出来 Astro Star 增长曲线还是很陡峭的,一直处于火热状态。

Asro Star 数变化趋势

Astro 的特点

1、群岛架构:一种基于组件针对内容驱动网站进行优化的 Web 架构。

Astro 开创并推广了一种叫做 “群岛” 的前端架构。群岛架构通过帮助你避免单体 JavaScript 模式并自动从页面中剥离所有非必需的 JavaScript,从而实现了更好的前端性能。开发者在使用 Astro 的同时,仍然可以继续使用他们最喜欢的 UI 组件和框架,并且从中得到受益。

“Etsy” 的前端架构师 Katie Sylor-Miller 在 2019 年首次创造了 “组件岛屿” 这个术语。随后,Preact 的创造者 Jason Miller 在 2020 年 8 月 11 日扩展了这个概念。

“群岛” 架构的总体思想不像看上去那么简单:在服务器上渲染 HTML 页面,并在高度动态的区域周围注入占位符或插槽 […] 这些区域随后可以在客户端 “激活” 成为小型独立的小部件,重用它们服务器渲染的初始 HTML。实践起来还是很有挑战性的。— Jason Miller, Preact 的创造者。

这种架构模式所依赖的技术也被称为 局部化或选择性激活。相比之下,大多数基于 JavaScript 的 Web 框架会将整个网站作为一个大型 JavaScript 应用程序(也被称为单页应用程序,或 SPA)进行激活和渲染。SPA 提供了简单性和强大的功能,但由于大量使用客户端 JavaScript 也导致存在一些页面加载的性能问题。SPA 在 嵌入 Astro 页面内 时也有其一席之地。但是,SPA 缺乏选择性和策略性激活的原生能力,使得它们对于当今大多数 Web 项目来说是一个笨重的选择。Astro 因为是第一个内置选择性激活的主流 JavaScript Web 框架而变得流行,它使用了由 Sylor-Miller 首次提出的组件岛屿模式。

在 Astro 中,“岛屿” 指的是页面上的任何交互式 UI 组件。你可以将岛屿想象成一个个交互式小组件,漂浮在静态、轻量级、服务器渲染的 HTML 海洋中。

群岛架构示意图,来源:Jason Miller

岛屿始终独立于页面上的其他岛屿运行,且一个页面上可以存在多个岛屿。尽管岛屿在不同的组件中运行,它们仍然可以共享状态并相互通信。这种灵活性使得 Astro 能够支持多个 UI 框架,如 React、Preact、Svelte、Vue 和 SolidJS。由于它们是独立的,你甚至可以在每个页面上混合使用多种框架。

【第2804期】Islands 架构原理和实践

Astro 群岛的最明显的好处就是性能:你网站的大部分区域都被转换为了快速、静态的 HTML,JavaScript 只有在需要的时候才会加载到各个组件中。JavaScript 是一个加载得最慢的资源。每一个字节都影响着用户的体验!

另一个好处是并行加载。在上面的一些假想例子中,重要性更低的图像轮播不应该阻挡更重要的页头部分的加载。它俩并行加载但独自激活(hydrate),这表明用户并不需要等着更沉重的图像轮播加载完毕就可以与页头交互了。

更好的地方在于:你可以准确地告诉 Astro 如何以及何时渲染每个组件。如果该图像轮播的加载成本真的很高,你可以附加一个特殊的客户端指令,告诉 Astro 仅在轮播在页面上可见时才加载它。如果用户从未看到它,它永远不会被加载。

2、UI 无关:支持 React、Preact、Svelte、Vue、Solid、Lit、HTMX、Web 组件等等。

正是由于 Astro 是群岛架构,每个组件是相互独立的,非常灵活。这种灵活性,使得 Astro 能够支持多个主流 UI 框架,如 React、Preact、Svelte、Vue、Solid 组件等。

【早阅】了解Astro 4.10中的环境变量和容器

下面从一个 demo 中来看 Astro 是如何去做多框架渲染的。

index.astro 中引入 React 和 Vue 组件

 ---
import Header from '../components/Header/index.tsx'
import Footer from '../components/Footer/index.vue'
---

<div>
<Header client:idle />
<Footer client:idle />
div>

React 文件内容

 import React from 'react';
export default function() {
return (
<div>
<p>react headerp>
div>
)
}

Vue 文件内容

 <script setup>
import { ref, onMounted } from 'vue'
const words = ref('vue footer')
onMounted(() => {
console.log(123)
words.value = 'vue footer 2'
})
script>

<template>
<div class="vue-footer-cont">
<p>{{ words }}p>
div>
template>

SSR 模式输出的 html 部分

 <astro-island
uid="r30xB"
prefix="r0"
component-url="/_astro/index.db5e9ed3.js"
component-export="default"
renderer-url="/_astro/client.802dacf3.js"
props='{"data-astro-cid-j7pv25f6":[0,true]}'
ssr=""
client="idle"
opts='{"name";"Header", "value":true}'
await-children=""
>
<div>
<p>react headerp>
div>

astro-island>

<astro-island
uid="X0T3U"
component-url="/_astro/index.6bfab11a.js"
component-export="default"
renderer-url="/_astro/client.6f88b9f8.js"
props='{"data-astro-cid-j7pv25f6":[0,true]}'
ssr=""
client="idle"
opts='{"name":"Footer", "value":true}'
await-children=""
>
<div class="vue-footer-cont" data-astro-cid-j7pv25f6="true">
<p>vue footerp>
div>

astro-island>
  • component-url:原始组件逻辑代码

  • renderer-url:组件渲染时需要的代码,如 React 的 jsx-runtime。通过改写,支持.astro 组件 renderToString。

从输出的 html 部分内容与 React 和 Vue 源码可以简单观察到,Astro 是使用 React 和 Vue 的 SSR 模式协助渲染输出内容。外边包一层自定义标签,标签属性记录一些岛屿组件状态、渲染和逻辑 js 代码地址等,用来实现传递数据,群岛按需加载,状态标记等功能。

3、服务器优先:将沉重的渲染移出访问者的设备。

在 Astro 中,大部分处理都是在服务器上进行,而非浏览器中。这通常使你的网站或应用在性能羸弱的设备或在较慢的互联网连接上查看时比客户端渲染更快

4、默认无 JS:让客户端更少的执行 JS ,以提升网站速度。

Astro 默认不使用客户端渲染。它们在构建时或使用服务器端渲染(SSR)按需呈现为 HTML,默认情况下不用任何 JavaScript。当需要交互必须写 js 时,可以利用客户端指令或者 inline script。

5、可定制:Tailwind、MDX 和数百个集成可供选择。

Astro 官方和社区提供了丰富的可定制的功能,比如多 UI 框架、多 SSR 托管平台适配器、Astro db、tailwind、MDX 等。只需要运行一行或几行命令,就可以为你完成必要的配置更改。

Web SSR 类框架性能对比

通过 CWV (Core Web Vitals,核心页面指标) 的网站百分比:使用特定框架的网站,通过谷歌核心网络指标评估的占比,通过意味着性能更好。

【第3387期】多种前端框架SSR性能大比拼

Astro 的 CWV 通过率最高,接近 70%

通过 CWV 的站点百分比

LCP 指标

通过 LCP 的站点百分比

FID 指标

通过 FID 的站点百分比

CLS 指标

通过 CLS 的站点百分比

通过谷歌的 CWV 测试,能看出来 Astro 的性能的确强劲。可以在我们的业务上做一些落地尝试。

项目实践

首先确定实践方向

在 APP 内的 H5:CSR 转向 SSR,减少前端的 js 体积。目前的前端业务,采用 React 和 Vue,大部分都是 CSR 渲染模式,js 体积庞大,性能并不是最优。SSR 和 SSG 能大幅减少体积,提升性能。

SEO 页面优化:当前主站 SEO 页面是基于 Vue 的 SSR+JQuery 模式,没有用框架。项目配置较复杂,上手成本较高。可以利用 Astro 的服务器优先策略,默认支持 SSR 模式。配置简单,上手成本低。UI 无关,可以不用框架,或者少用框架,即可快速搭建页面。

活动类型的业务:当前业务中,存在多技术栈的组件,Vue 和 React 组件均有,可以利用 UI 无关的特点,利用已有组件快速搭建活动页面。

示例项目

下面以业主认证页面为例子,介绍一下一些实践细节。以下是一个内容展示页面,用于介绍业主认证的一些流程和好处。

内容展示页面示例图

项目示意代码

主文件

 ---
export const prerender = false
import Layout from '../layouts/Layout.astro'
import Page from '../components/BrokerOwnerCheck/posterToC/index'
import { url } from './api'

const data = await fetch(url)
---

<script src="lib-flexible/flexible">script>
<Layout title="业主品牌馆">
<Page data={data} />
Layout>

主文件是个 Astro 文件:

  • prerender 是配置当前页面预渲染状态,因为项目是配置的 hybrid 模式,所 prerender=false 才能启动实时渲染(文档地址:https://docs.astro.build/zh-cn/getting-started/);

  • Layout 是 Astro 组件,用来放置公共 Layout 代码,像页面 head 标签内一些公共内容和公共底部等;

  • Page 是 React 组件,大部分逻辑都放在 React 组件中;

Page 组件

 import styles from './index.module.less';

export default ({ data }) => {
const renderTitleBox = (title) => {
return <div className={styles.titleBox}>
<span className={styles.titleText}>{title}span>
div>
};

const renderTextBox = (role, text) => {
return <div className={styles.textBox}>
<div className={styles.textIcon}>Adiv>
<div className={styles.text}>
<span style={{ fontWeight: 700, color: '#333' }}>{role}span>
<span>{text}span>
div>
div>
};
return (
<div className={styles.posterContainer}>
<img className={styles.headPoster} src={data.img1} />
<div className={styles.moduleBox}>
{ renderTitleBox(data.title1) }
{ renderTextBox(data.desc1) }
{ renderTextBox(data.desc2) }
div>
<div className={styles.moduleBox}>
{ renderTitleBox(data.title1) }
<img className={styles.poster} src={data.img2} />
div>
div>
)
};

很标准的 React 写法,数据从上层传过来,拿到数据进行填充到对应位置。整体写法采用的是以 React 组件为主,Astro 入口文件为辅。从代码层面可以看出来对前端同学开发非常友好,上手几乎零成本。还可以兼容各个 UI 框架的组件。

性能对比

在页面资源方面,使用 Astro 开发,页面 js, css, html 资源约占 6.6KB,且没有 js 渲染。如果使用传统 React 客户端渲染开发,页面 js, css, html 资源约占 150KB,且还需要 js 渲染。两者资源体积相差 20 + 倍。

借助 Lighthouse 进行评估,Astro 框架也整体优于 React

Astro 开发页面 Lighthouse 评估效果

React 开发页面 Lighthouse 评估效果

可以看出整体性能 Astro 开发是优于传统 React 客户端渲染开发。

最佳实践

开发 Astro 项目和我们用 React Vue 等开发客户端渲染形式页面开发思路还是有区别的,如果还用常规思路开发,Astro 性能效果会打一定折扣。下面介绍一下常见 “误区” 及如何解决。

在引入 react vue 等组件的时候通常会遇到如下图报错

报错示例图

这个报错提示:浏览器 API 不能在 node 中使用。或者使用指令更改渲染方式。这个时候查看文档链接通常都会使用文档中 client:only="react" 这个指令来解决这个报错。但是使用这个指令 Astro 会将我们的组件进行客户端渲染,这样就失去 Astro 的 SSR 部分优势。

报错原因:因为渲染 React 组件会在 node 端运行,node 端不支持浏览器特有的 API。所以当我们运行一些浏览器特有 API 会报异常。那么如何发挥 Astro 最大优势去做开发?最好的方式是调整开发逻辑,规避在 node 中使用浏览器 API。下面推荐代码结构来讲解一下。

整体推荐代码结构示例图

React 文件示例推荐代码结构

小结:React、 Vue 分别在各自的 useEffect onMounted 方法中和在交互事件绑定的方法中才能使用浏览器 API。

总结:区分场景,按场景来使用浏览器或 node 特有 API。

目前在我们保障专区、安心租 PC/APP 的活动邀请、业主认证 C 端引导页已经完成了项目落地实践。相对于之前的开发模式,页面性能和开发者体验都提升不少。

但实践过程也发现 Astro 不足之处:Astro 静态资源前缀地址只支持一种前缀地址配置。但是我们业务中通常不止一个 CDN 地址。

在 build.assetsPrefix 选项中:

build.assetsPrefix 选项展示

如果有多种情况,比如 css 文件 CDN 地址前缀是 https://css.58.com/static/css, js 文件 CDN 地址前缀是 https://js.58.com/static/js。其它文件地址是 https://imgs.58.com/static/imgs。
Astro 就不支持了。此时对 Astro 比较熟悉的同学会提出疑问:Astro 支持 vite 配置扩展,vite 里不是有针对多 CDN 地址前缀的配置嘛?没错是的,但是,配置后你会发现几乎不起作用。提了 issues(https://github.com/withastro/astro/issues/9700#issuecomment-1907226632) 之后与核心开发者确认沟通,Astro 确实无法支持多 CDN 配置。

Pull Request

不支持那么就开始尝试提 PR 来支持这个功能。

一些小技巧

提 PR 有些小技巧,要循序渐进的参与到开源项目中,何为循序渐进呢?先提 issues 与作者讨论,先混个 “脸熟”,再提少量代码的 PR,逐渐的代码量可以随着 PR 次数逐渐增多而增多。通过不断增多的沟通次数,逐渐提升你与作者之间的 “亲密度”。这样的好处是能逐渐的了解整体架构和作者的设计思路,在做改动的时候不会破坏整体的设计,作者也更容易接受你的改动。不提倡突然大量代码的 PR!

API 设计 & 开发

开发第一步,先设计 API,首先要兼容原有的 API 使用形式,而且灵活性要好,能适用各种场景。所以最终受 vite 配置启发,也采用函数的形式。

也使用 build.assetsPrefix 选项,当前 assetsPrefix 只支持字符串类型。添加函数类型,返回值为前缀字符串。

 // assetsPrefix function
import { defineConfig } from 'astro/config';
export default defineConfig({
build: {
assetsPrefix: (fileType) => {
if (fileType === 'js') {
return 'https://js.example.com/'
} else if (fileType === 'css') {
return 'https://css.example.com/'
}
return ''
}
}
});

按这种 function 类型开发完并提交 PR 进行初次审核与讨论 PR1 (PR 地址:https://github.com/withastro/astro/pull/9898#issuecomment-1951878995)
通过 PR1 作者反馈在 SSR 场景下会不生效,建议使用对象的形式:

PR1 作者的反馈

但我还是想用函数的形式,于是尝试修复 SSR 场景不生效问题。

经排查,SSR 场景构建时候会对配置进行 JSON.stringify 导致方法丢失。

SSR 场景构建时对配置进行 JSON.stringify 源码位置

Astro 构建项目的时候 SSR 场景会将配置部分内容进行打包到构建产物中,这种形式如果我们使用函数配置选项的话会对项目改动比较大,所以最终采纳作者建议使用对象的形式。最终经过多人反复讨论使用方法如下最新文档。(PR 地址:https://github.com/withastro/astro/pull/10189#event-12055572178)。

assetsPrefix 最新文档

展望规划

  • 解决完这个问题,在后续项目实践中就没有什么障碍了。

  • 后续充分发挥 Astro 框架能力,优化业务页面体验。

  • 以活动专题页开始试点 Astro 框架应用

  • 搭建标准化开发框架,更多应用场景试点

  • 基于 Astro 搭建一种 “高效能服务端渲染平台”,可以快捷地生产高性能页面

关于本文
作者:@张志鹏
原文:https://mp.weixin.qq.com/s/Wcuzte415I0kXM6tebP22Q

这期前端早读课
对你有帮助,帮” 
 “一下,
期待下一期,帮”
 在看” 一下 。