写点什么

服务端来自火星,客户端来自金星,RSC 开发新思路

作者:Michael Shilman

  • 2024-01-13
    北京
  • 本文字数:2804 字

    阅读完需:约 9 分钟

大小:1014.13K时长:05:46
服务端来自火星,客户端来自金星,RSC开发新思路

将 Storybook 升级到 8.0alpha 版本,可支持 React 服务端组件。

 

在基于 React 的 Web UI 开发中,React服务端组件(RSC)是一种新的编程模式。与传统的 React “客户端”组件不同,它们只在服务器上进行渲染。这为性能和安全方面带来了一些好处,但与当下的各种 React 工具和库相比,其用法有很大的差异。

 

其中受影响最大的领域之一就是基于组件驱动的开发和测试。诸如 Storybook、Testing Library 以及用于组件测试的工具 Playwright 和 Cypress,全都是假设用户组件在浏览器(或 JSDom)中进行渲染。但是对于服务器组件来说,情况就不再是这样了。

 

因此,这就引出了一个问题:该如何独立进行服务器端组件的开发和测试呢?

 

今天,我很高兴地宣布,Storybook 的 Next.js 框架将提供 RSC 支持,算是作为上述问题的一个尝试性的解决方案。由于它是一个纯客户端实现,所以能很好的集成和适配整个 Storybook 插件生态。

 

本文介绍了它的工作原理和用法,并提供了一个简单的教程。

 

服务端来自火星,客户端来自金星

 

RSC 与传统的客户端组件有两个主要区别,如下代码所示:

 

// ApiCard.tsximport { ComponentProps } from 'react';import { Card } from './Card';import { findById } from './db';export async function DbCard({ id }: {id: number}) {  let props;  try {    const contact = await findById(id);    props = { state: 'success', contact };  } catch (e) {    props = { state: 'error' };  }  return <Card {...props} />;}
复制代码

 

  1. 第一个区别是:服务端组件是异步的,而这在客户端上是不支持的。

  2. 第二个区别是:服务端组件可以直接访问 Node 代码,在这个示例中,函数 findById 封装了一个经过验证的数据库连接。

 

为了实现这两点,RSC 在底层做了很多事情。这段代码只能在服务器上运行,并生成一个静态的、类似 JSON 的结构,然后通过流的方式传输给客户端。

 

Storybook 是一个纯客户端应用。它是一个用于生成纯 HTML/CSS/JS 的静态构建,没有任何 Node 的影子!因此,如果要支持 RSC,就需要解决两个问题:要么找出如何在客户端上渲染 RSC 的方法,要么为服务端渲染重构 Storybook。

 

我们首先专注于客户端方法。这是因为,我们希望最大程度地减少对用户的影响,毕竟这些用户已经在当前的架构下编写了数百万个用例和上百个插件。

 

那么,它到底是如何实现的呢?

 

开始支持异步

 

如何支持异步组件是在客户端上渲染 RSC 组件的第一个挑战。幸运的是,在 Next.js 最新依赖的 React 版本中已经(非官方地)支持了这一功能。我们要特别感谢JamesManningRjulRuss,他们为此提供了一个简单的解决方案!

 

import { Suspense } from 'react';export const ClientContact = ({ id }) => (  <Suspense><DbCard id={id} /></Suspense>);
复制代码

 

从 Storybook 8 开始,通过在.storybook/main.js 中开启 experimentalNextRSC 特性,@storybook/nextjs 就会自动将你的 story 封装在 Suspense 中:

 

// .storybook/main.jsexport default {  features: {    experimentalNextRSC: true,  }};
复制代码

 

在 @storybook/nextjs 7.x 版本中,你也可以手动将 RSC story 封装到装饰器中。

 

注意:这个解决方案目前还不能在其他 Storybook React 框架(例如 react-vite、react-webpack5)中使用,因为它们没有像 Next.js 那样使用 canary 版的 React。希望下一个 React 版本能消除这个限制。

 

模拟和加载


解决异步问题只解决了一半的问题。为了完成组件数据的填充,我们的 DbCard 组件是通过调用 Node 代码获取数据。然而,Node 代码在浏览器中无法执行,这就导致了问题!

 

为了解决这个问题,我们建议搭建一个干净的数据访问层。这也是RSC架构师推荐的最佳实践。

 

创建好数据访问层后,你就可以在浏览器中通过模拟来运行它,并精确控制返回的数据,展示不同的用户界面状态(加载中、错误、成功等)。

 

你可以使用模块模拟网络模拟来模拟数据访问层,这两种方式 Storybook 都支持。

 

模块模拟:有一个叫做storybook-addon-module-mock的社区插件,它提供了和 jest.mock(仅适用于 Webpack 项目)类似的模拟功能。当然,也可以使用webpack/vite的别名实现一个简单但功能有限的解决方案。我们计划在 Storybook 的未来版本中提供更便捷的模块模拟功能。

 

网络 API 模拟:为了模拟网络请求,我们推荐使用Mock Service Worker (msw)。当然 Storybook 还支持许多其他网络GraphQL模拟插件。

 

回到上面的例子,下面是一个使用了 storybook-addon-module-mock 的 story:

 

// DbCard.stories.jsimport { StoryObj, Meta } from '@storybook/react';import { createMock } from 'storybook-addon-module-mock';import { DbCard } from './DbCard';import * as db from './db';export default { component: DbCard };export const Success {  args: { id: 1 },  parameters: {    moduleMock: {      mock: () => {        const mock = createMock(db, 'findById');        mock.mockReturnValue(Promise.resolve({          name: 'Beyonce',          img: 'https://blackhistorywall.files.wordpress.com/2010/02/picture-device-independent-bitmap-119.jpg',          tel: '+123 456 789',          email: 'b@beyonce.com'        }))        return [mock];      },    },  },}
复制代码

 

完整 Demo:API+模块模拟


要了解完整示例,包括使用模块模拟数据库版本和使用 MSW2 模拟 API 版本,请查看完整StorybookRSC示例GitHub仓库



有什么问题吗?


在本文中,我们成功地在 Storybook 中为 RSC 编写了第一个 story,并展示了这一切是在幕后是如何实现的。

 

虽然所有事情都相当的简单明了,但是这种方法还是会有一些限制:

 

  1. 保真度:纯客户端实现与在应用程序中实际运行的服务端流式 RSC 相比依然存在显著的差异。

  2. 便利性:这里的模拟解决方案肯定还有改进的空间。当前的模块模拟解决方案不仅冗长,且与 Storybook 的参数/控件也兼容的不够好。

 

我们计划在后续的迭代中解决这两个问题,这也是为什么我们将此解决方案标记为实验性的原因。

 

现在就在 Storybook 中进行 RSC 开发吧

 

要使用 Storybook 进行 RSC 开发,请将 Storybook 升级到 8.0-alpha 版本:

 

npx storybook@next upgrade --prerelease
复制代码

 

然后,在项目的.storybook/main.ts 文件中将实验性功能开启:

 

// .storybook/main.jsexport default {  features: {    experimentalNextRSC: true,    },  };}
复制代码

 

更多信息,请参阅 @storybook/nextjs 的README文档

 

本文是详细介绍 Storybook 8.0 的第一篇文章,在接下来的几个月里我们将发布更多的内容。请关注我们的社交媒体或订阅Storybook新闻资讯,获取 Storybook 下个版本的全部信息!

 

原文地址:https://storybook.js.org/blog/storybook-react-server-components/

 

相关阅读:


从 Styleguidist 迁移到 Storybook

HTML5 Web Sockets 与代理服务器交互

从新 React 文档看未来 Web 的开发趋势

如何快速构建 React 组件库

2024-01-13 08:007990

评论

发布
暂无评论
发现更多内容

新华网专访 | 用友网络:中国企业“出海”要有全球视野 需构建数智化全球人才供应链

用友BIP

人力资源 中企出海

以开放安全底座赋能全球开发者,华为云构筑云原生安全防护体系

华为云开发者联盟

云计算 华为云 华为云开发者联盟 企业号 7 月 PK 榜

问答对话文本数据:解锁智能问答的未来

数据堂

领域知识图谱的医生推荐系统:利用BERT+CRF+BiLSTM的医疗实体识别,建立医学知识图谱,建立知识问答系统

汀丶人工智能

人工智能 自然语言处理 深度学习 知识图谱 智能问答

衡阳等保测评中心地址在哪里?电话多少?

行云管家

等保 等级保护 等保测评 衡阳

ScaleBit 与 NFTScan 达成安全生态合作伙伴关系

NFT Research

安全 NFT\

DPO 直接偏好优化:跳过复杂的对抗学习,语言模型本来就会奖励算法

Zilliz

AIGC LLM RLHF

华为云MetaStudio全新升级,盘古数字人大模型助力数字人自由

华为云开发者联盟

人工智能 华为云 数字人 华为云开发者联盟 企业号 7 月 PK 榜

语音标注平台:推动语音技术发展的关键支撑

数据堂

华为云云原生数据库,让企业离应用更进一步

新消费日报

ZipZapAI大模型与勇者斗恶龙:探索AVG游戏的无限可能

Ricky

AI Chat ChatGPT

Python源码剖析:深度探索Cpython对象-达观数据

NLP资深玩家

Python CPython 达观数据

数据安全没保证?GaussDB(for Redis)为你保驾护航

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 企业号 7 月 PK 榜

基于知识图谱的电影知识问答系统:训练TF-IDF 向量算法和朴素贝叶斯分类器、在 Neo4j 中查询

汀丶人工智能

人工智能 自然语言处理 深度学习 知识图谱 智能问答

数据孤岛、系统林立,这些顽疾瓴羊想要全搞定

ToB行业头条

从大数据到AI,华为云存储加速企业大模型快速应用

华为云开发者联盟

云计算 后端 华为云 华为云开发者联盟 企业号 7 月 PK 榜

首个!AI开发者创作激励计划开启,有成长、有收入

飞桨PaddlePaddle

人工智能 百度 paddle 飞桨 百度飞桨

HiveSQL 迁移 FlinkSQL 在快手的实践

Apache Flink

大数据 flink 实时计算

统一技术底座助力医疗机构数智化转型

用友BIP

数智底座 技术底座

消费品行业全面预算管理领先实践

用友BIP

全面预算

C++ 测试框架 GoogleTest 初学者入门篇

不在线第一只蜗牛

编程 测试框架 C++

点云标注的标准化与数据共享

数据堂

超高速稳定!香港虚拟主机助你网站飞一般的速度!

一只扑棱蛾子

香港虚拟主机

用友iuap:最懂企业级技术,更懂企业级业务

用友BIP

国产替代

24款好用的电脑画图软件推荐,总有一款适合你!

彭宏豪95

效率工具 软件 流程图 画图软件 绘图工具

如何评价MyBatis-Flex框架

酱紫的小白兔

柏睿数据:以自主可控的智能算力引擎服务数据产业创新发展

新消费日报

成就数智企业,用友助力中国企业迈向高质量发展

用友BIP

国产替代

秒验丨 REST API:手机号码置换接口

MobTech袤博科技

大数据 前端 后端

服务端来自火星,客户端来自金星,RSC开发新思路_跨端开发_InfoQ精选文章