50万奖金+官方证书,深圳国际金融科技大赛正式启动,点击报名 了解详情
写点什么

服务端来自火星,客户端来自金星,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:007971

评论

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

AI入门之深度学习:基本概念篇

京东科技开发者

一招致胜!天翼云对象存储攻克数据存、管、用难题!

天翼云开发者社区

云计算 对象存储 云服务 天翼云

3 x 2 + 1 !安 全 能 力 权 威 认 可 !

天翼云开发者社区

云计算 安全 天翼云

最佳实践:解读GaussDB(DWS) 统计信息自动收集方案

不在线第一只蜗牛

Java 人工智能 GuassDB

全国高校软件测试开发教学师资培训会圆满落幕

测吧(北京)科技有限公司

测试

实际上手体验maven面对冲突Jar包的加载规则

京东科技开发者

课件ppt怎么做?3个在线网站轻松制作教学ppt!

职场工具箱

效率 职场 PPT 办公软件 AI生成PPT

并发性能提升 4 倍!云帐房用 Serverless 轻松应对瞬时业务洪峰

阿里巴巴云原生

阿里云 Serverless 云原生

六个策略,打造网络安全宣传周峰值体验

我再BUG界嘎嘎乱杀

网络安全 信息安全 网络安全宣传周

从理念到实践,解构HBlock降本增效黑科技!

天翼云开发者社区

数据库 云计算 存储 天翼云

【YashanDB数据库】Mybatis-plus分页框架识别不到Yashandb

YashanDB

yashandb 崖山数据库 崖山DB

如何制作巡逻巡更二维码?扫码就能快速上报异常情况

草料二维码

设备巡检 草料二维码 二维码系统 巡逻巡更二维码 巡逻巡更

什么是DNS缓存?DNS缓存有哪些作用和危害?

防火墙后吃泡面

【网络安全】Web Hacking网络黑客手册,GitHub星标3.7K!

我再BUG界嘎嘎乱杀

黑客 网络安全 安全 信息安全 网安

怎么用云手机进行TikTok矩阵运营

Ogcloud

云手机 海外云手机 tiktok云手机 云手机海外版 tiktok矩阵

云手机在海外社交媒体运营中的作用

Ogcloud

云手机 海外云手机 云手机海外版 海外社媒运营 海外社媒营销

【YashanDB数据库】由于网络带宽不足导致的jdbc向yashandb插入数据慢

YashanDB

yashandb 崖山数据库 崖山DB

Forrester Wave™报告:天翼云三项产品能力获评最高分!

天翼云开发者社区

云计算 公有云 云平台

AI自动化应用开发,让创意与效率并驾齐驱!

测吧(北京)科技有限公司

测试

AI 时代,网关更能打了?

阿里巴巴云原生

阿里云 云原生 网关

跨越边界:京东商品详情API的全球拓展之旅

代码忍者

拼多多API接口:通过商品ID获取拼多多商品详情数据接口

tbapi

拼多多商品详情接口 拼多多API 拼多多商品数据采集

如何成为网络安全架构师?

我再BUG界嘎嘎乱杀

黑客 网络安全 信息安全 架构师 网安

比特币领涨,反转行情即将开启?市场双位数反弹与未来展望

区块链软件开发推广运营

dapp开发 区块链开发 链游开发 NFT开发 公链开发

【YashanDB数据库】PHP无法通过ODBC连接到数据库

YashanDB

yashandb 崖山数据库 崖山DB

mac专业图表绘制软件:OmniGraffle Pro for mac 激活版

你的猪会飞吗

Mac软件下载站 mac破解软件下载

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