服务端来自火星,客户端来自金星,RSC 开发新思路
创始人
2024-01-15 16:51:50
0

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

作者 | Michael Shilman

译者 | 许学文

策划 | 丁晓昀

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

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

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

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

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

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

服务端来自火星,

客户端来自金星

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

// ApiCard.tsx import{ ComponentProps } from'react'; import{ Card } from'./Card'; import{ findById } from'./db'; exportasyncfunctionDbCard({ id }: {id: number}) { letprops; try{ constcontact = awaitfindById(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 版本中已经(非官方地)支持了这一功能。我们要特别感谢 JamesManningR 和 julRuss,他们为此提供了一个简单的解决方案!

import{ Suspense } from'react'; exportconstClientContact = ({ id }) =>( <Suspense><DbCardid={id}/>Suspense> );

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

// .storybook/main.js exportdefault{ 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.js import{ StoryObj, Meta } from'@storybook/react'; import{ createMock } from'storybook-addon-module-mock'; import{ DbCard } from'./DbCard'; import* asdb from'./db'; exportdefault{ component: DbCard }; exportconstSuccess { args: { id: 1}, parameters: { moduleMock: { mock: ()=>{ constmock = 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 版本:

npxstorybook@nextupgrade --prerelease

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

// .storybook/main.js exportdefault{ features: { experimentalNextRSC: true, }, }; }

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

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

原文地址

https://storybook.js.org/blog/storybook-react-server-components/

相关阅读

从 Styleguidist 迁移到 Storybook(https://www.infoq.cn/article/SSjTSB0H2NPb02wwOJxz?utm_campaign=geek_search&utm_content)

HTML5 Web Sockets 与代理服务器交互 (https://www.infoq.cn/article/Web-Sockets-Proxy-Servers?utm_campaign)

从新 React 文档看未来 Web 的开发趋势 (https://www.infoq.cn/article/Tv3SyqoivXMWUoj8qSMT)

如何快速构建 React 组件库 (https://www.infoq.cn/article/6s2QNpu3EvR0LS5mHa3b?utm_campaign)

声明:本文为 InfoQ 翻译,未经许可禁止转载。

点击底部阅读原文访问 InfoQ 官网,获取更多精彩内容!

今日好文推荐

并发王座易主?Java 21 虚拟线程强势崛起,Go & Kotlin还稳得住吗 | 盘点

谷歌新年大裁员,引硅谷裁员潮!OpenAI正式推出GPT Store,但第一批应用已被像素级抄袭;腾讯服务器深夜崩溃 | Q资讯

纯向量数据库和向量插件都有局限,那未来发展有其他方向吗?

系统 bug 致百人入狱,砸了 2.8 亿元仍上云失败!二十年了,这家大企业被日本软件坑惨了

相关内容

热门资讯

带学生斩获160多个大奖!这名... 在AI和机器人火热的当下 谁能想到 早在2005年 海宁就诞生了 第一批学校机器人社团 此后更是拿奖...
(经济观察)广东加速打造人工智... 广州6月7日电 (记者 孙秋霞)近年来,广东密集出台一系列支持人工智能与机器人产业创新发展的政策措施...
原创 人... 人形设计的核心必要性,环境适配性:人类社会的物理环境(如门把手、楼梯、工具)均以人体工程学为基础设计...
柬埔寨官员呼吁中国企业助力柬农... 金边6月7日电 (记者 杨强)由中柬两国企业合作建设的柬埔寨首个香蕉供应链气体负压催熟库当地时间6日...
格力电器获得发明专利授权:“换... 证券之星消息,根据天眼查APP数据显示格力电器(000651)新获得一项发明专利授权,专利名为“换热...
武陟:梯度培育赋能企业“拔节生... 河南日报客户端记者 成安林 通讯员 成睿 6月6日,位于武陟经济技术开发区的焦作赛科中药生物科技有限...
准备干掉360整个市场部?周鸿... 每经AI快讯,6月6日晚间,360集团创始人、董事长周鸿祎在其个人微博账号发文称,“我准备干掉360...
“超越日本,中国首次跃居首位” 据《日本经济新闻》网站6月4日报道,中国在氢相关专利竞争力方面超越日本,首次跃居首位。中国企业主要在...
2025 年性价比超强的 6 ... 2025 年性价比超强的 6 款 512G 大内存手机:从地铁通勤到高原徒步,哪台是你的「搬砖神器」...
字节跳动CQC前掌门李彤离职,... 近日,字节跳动内部传出一则重要人事变动消息,其内容质量中心(Content Quality Cent...
电脑主机:数字世界的核心引擎 现代生活中,电脑已成为工作娱乐的重要工具。当我们注视显示器时,机箱里正进行着复杂的电子交响乐。这个方...
网络优化、智能屏蔽、应急保障…... 天津北方网讯:6月7日,2025年全国高考正式拉开帷幕。天津电信组建专业保障团队,通过网络优化、智能...
爱仕达获得实用新型专利授权:“... 证券之星消息,根据天眼查APP数据显示爱仕达(002403)新获得一项实用新型专利授权,专利名为“一...
大林橡胶取得一种振动筛料机构专... 金融界2025年6月7日消息,国家知识产权局信息显示,河南大林橡胶通信器材有限公司取得一项名为“一种...
卡奥斯等申请检修一体机专利,无... 金融界2025年6月7日消息,国家知识产权局信息显示,卡奥斯创智物联科技有限公司;佛山领智物联科技有...
三年、千亿陪伴新兴技术穿越产业... 当下,国内人工智能和机器人产业发展如火如荼,当各行各业开始千方百计拥抱人工智能和机器人产业之时,政府...
奥佳华获得发明专利授权:“颈背... 证券之星消息,根据天眼查APP数据显示奥佳华(002614)新获得一项发明专利授权,专利名为“颈背按...
上海淇玥信息技术申请去除内生性... 金融界2025年6月7日消息,国家知识产权局信息显示,上海淇玥信息技术有限公司申请一项名为“去除内生...
消息称苹果公司正扩大平台“游戏... IT之家 6 月 7 日消息,此前有许多消息显示苹果公司将在 WWDC25 中推出全新独立游戏应用,...
AI智能体未来之路:管控还是信... 在AI技术日新月异的当下,图灵奖得主、蒙特利尔大学教授Yoshua Bengio的声音尤为引人关注。...