搭建 Hydrogen —— 一个搭建自定义商店的 React 框架
在过去的一年多的时间里,我们在一直在搭建 Hydrogen。Hydrogen 是 Shopify 上的一个构建自定义店面的 React 框架。我们采用了最先进的技术,比如 React 服务器组件(RSC),来确保开发人员在 Shopify 平台搭建应用时有一个美好的体验。
本文是搭建 Hydrogen 的幕后故事,讲述我们在搭建过程中学到的经验和教训,以及采用实验技术从零开始搭建一个新框架的感受。
为什么要搭建 Hydrogen?
我们搭建 Hydrogen 是为了解决商家(尤其是大型商家)面临的一个问题:如何使用 Shopify 的店面 API 搭建自定义的商店,同时还能享受 Liquid 店面提供的免费服务? 虽然搭建全定制店面对商家来说有很多好处,但他们也面临一些问题,比如选择框架、为购物车和产品选择搭建基元、性能、测试、可访问性、托管、扩展、可观察性和分析等问题。
Hydrogen 诞生之前,商家使用的其他框架要么需要从庞大的模板入手,要么得从零开始搭建。我们认为商业在本质上是动态的,而面向 JAMStack 的框架建立的是静态网站,且需要不断重新进行构建,这并不是 Shopify 的最佳选择,所以我们倾全力打造了 Hydrogen。Hydrogen 是一个由 React 驱动的动态自定义店面框架,致力于为商家解决上述所有问题,节省开发时间,为开发人员提供顶级的开发体验。
迭代-运输-迭代
2021 年 4 月 1 日,我们创建了一个新的空 GitHub 仓库,命名为 Shopify/hydrogen
。 当时我们不知道在搭建什么,也不知道会有什么成果。我们一共发布了 1200 多个拉动请求和 3000 个提交,才有了大家今天看到的 Hydrogen。
在不断的试错中,我们学到了很多东西。我们之前以为新的组件会很有用,但后来发现组件没有用,就把它们删除了。我们引入了新的功能,但也引入了新的 bug。 Hydrogen 的早期使用者和现在正在使用 Hydrogen 的商家给我们提供了至关重要的反馈,我们也解决了反馈里提出的问题。
组件,你好!再见!
其中一个迭代的例子是我们的组件列表,最初的组件列表包括 Product
和 SelectedVariant.AddToCartButton
。我们原以为开发人员会喜欢用 Product
组件包装产品详情页,并能访问像 SelectedVariant.AddToCartButton
这样的“神奇”子组件,这些组件能进入 React 上下文,与周围的组件进行交互。
但很快我们就收到用户反馈说这些组件太死板了:这些组件要求有一定的 GraphQL 有效载荷, 所以开发人员不能修改查询,也不能包含第三方的自定义数据,但这是定制店面的常见需求,所以我们搭建的组件虽然很全面,但没什么实际意义。
最后,我们删除了许多组件,获得了一个更精简的框架,只提供对开发人员真正有用的基元。
获取还是不获取(在 React 框架中)
在数据获取的工作原理方面,我们也经历了一个更新和进化的过程。在开发 Hydrogen 的早期,我们决定使用服务器组件和 React 18 的流式服务器端渲染(SSR),这意味着服务器上要有一个相应的数据获取。
其他框架提供顶层路由数据获取工具,如 loader()
或 getStaticProps()
。我们没有创造另一个定制加载器 API,而是在 Hydrogen 中搭建了组件级的数据获取功能。
单纯执行组件级数据获取时会面临一些问题。例如,如果在嵌套的组件中请求数据,很容易引起网络请求瀑布流,因为如果前一个组件没完成渲染,那么每个后续的组件的渲染都被阻止。
为了解决这些问题,我们搭建了一个预加载缓存,吊起嵌套的数据查询来并行执行。启用后,预加载的查询会在页面被请求时立即开始运行,来满足后续请求,而不是以瀑布流的模式。
我们希望这个功能能帮助开发人员,所以我们还建立了一个实验性的查询计时记录器,当页面检测到网络请求瀑布流时,会提醒开发人员,这是开启预加载进行查询的提示。我们目前仍在积极探索这个领域,预计 React 生态系统最终会朝这个方向发展,我们很期待能看到一些新的解决方案。
不再使用片段
在 Hydrogen 开发者预览版的早期,我们从几个 UI 组件中导出了包含 GraphQL 片段的字符串。我们想通过插入所需的数据,将它们作为片段呈现给服务器上的查询,从而简化 UI 组件的使用步骤。
随着时间的推移,我们为这些 UI 组件添加了更多的功能,这意味着我们需要更多的数据来保证组件的正常工作,这就导致了更大、更复杂的片段,包括使用必要的变量、 大的默认分页值、以及许多的元字段和变体的节点。
我们很快发现,这些片段变得很臃肿。每创建一个新的 Hydrogen 应用,开发人员都要获取非常多不必要的数据,导致页面加载速度比从头开始编写查询还要慢。更糟糕的是,片段本身的内容被掩盖在了 Hydrogen npm 包中,很难发现正在请求什么数据。为解决这个问题,我们做了两件事。
首先,我们创建了一个新的实验性记录器来检测 GraphQL 查询中未使用的属性。当开发人员请求的数据没有在组件中使用时,记录器就会提醒他们,建议他们从页面删除这些字段来提高性能。
Hydrogen 的 DevTools 为开发人员提供有用的提示,来提高其自定义店面的速度和性能。
第二,我们把 Hydrogen npm 包中的所有片段输出几乎都删除了,导致新搭建的 Hydrogen 应用程序中会有更多繁琐的查询,但这样开发人员更容易发现查询的数据。这有利于开发人员根据自己的需求对查询进行微调,而不依赖片段。
通过这两个调整,我们获得了非常不错的成果:Hydrogen 的 demo 商店模板中一些路线的加载时间缩短了一半。我们目前仍在对这些工具进行实验,同时也在寻找引入片段的更好的方式,从而让刚接触 GraphQL 的开发人员更快上手。
在开源环境中搭建
将 Hydrogen 作为一个公共的开源项目来搭建的好处之一是可以获得外部开发人员的贡献。例如,为 useShopQuery 增加一个新的选项,防止 demo 商店模板中的错误,以及增加国际化支持。事实上,自 2021 年 11 月以来,Hydrogen 已经获得了十几个外部开发人员的贡献。
开源搭建的另一个好处是,我们可以通过讨论和问题获得外部开发人员的反馈。我们提出了我们最初的路由策略并得到了反馈,对我们缓存 API 进行了调整。开发人员强烈建议我们在 demo 商店模板中使用 TypeScript,于是我们就采纳了!
敢于冒险
2021 年初,我们着手搭建 Hydrogen 时,承担了很大风险,但我们相信随着时间的推移,我们使用的技术将不断改进,通过不断试错,不断学习,从而做出更好的计划。以下是我们这次冒险的几个亮点,以及这几次冒险如何成就了现在的 Hydrogen。
React 服务器组件(RSC)
2020 年 12 月,React 发布了 React 服务器组件(RSC),当时这是一个仍在开发中的功能,可以让 React 组件在服务器上渲染,不需要客户端 JavaScript,从而加快了页面渲染速度。快进到 2021 年 4 月,当时我们正在考虑在 Hydrogen 中建立什么样的数据获取 API。
我们在 Slack 频道中感叹 RSC 模式是最理想的,可惜当时它还没有发布。
我们没有等待,决定搭建一个能在 Vite 中运行的版本,并立即开始使用。我们单纯实现了(基于一些逆向工程)RSC 有效载荷,该载荷将 React 组件序列化,并让组件在浏览器中互动。
这是 2021 年 5 月在我们的私有 Hydrogen 库里切换到服务器组件的 PR 截图,然后我们在 2021 年 11 月随着开发人员预览的发布切换到公共库。
这个操作能够推动搭建一个基于服务器组件的框架,并支持组件级的数据获取等,不用等服务器组件的最终生产版本(可能是几个月或几年后)。
我们最终改用了由 React RSC 有效载荷驱动的官方版本的服务器组件。
RSC 是目前为止我们在 Hydrogen 上做出的最大的技术赌注。我们相信它提供了客户端和服务器组件之间的完美分离。它从第一方和第三方代码库中混合和匹配服务器组件的能力创造了一种模块化,这是其他框架所无法比拟的。我们不可能将一个在服务器上获取数据的组件放到一个非 RSC 框架中,因为其他框架要求数据获取发生在路由层。有了 RSC,服务器组件可以被添加到 Hydrogen 应用程序中,并且可以立即使用。第三方开发人员是 Shopify 生态系统的生命线,这对 Hydrogen 来说非常有意义。
Hydrogen 为开发人员提供了使用 React 服务器组件支持定制店面的工具。
我们正在与 Meta 的 React 核心团队和 Vercel 的 Next.js 团队紧密合作,迭代和完善服务器组件的设计。我们已经对服务器组件中提出的服务器模块惯例进行了反馈,正在努力寻找一个对所有开发人员都最有效的 API。在解决最后的细节问题时,Hydrogen 和 Next.js 将持续更新服务器组件 API 规范。
我们也认识到,认真编写文档是促使大家使用我们的应用的关键,所以我们在 Hydrogen 的上下文中编写了服务器组件的相关文档,并会不断地优化我们的文档,帮助今后使用服务器组件的社区成员。
Vite
一年前,webpack 是大多数前端项目的首选捆绑器。它确实是一个很好的工具,但我们决定用 Vite 作为 Hydrogen 的捆绑器。
在 Vite 上搭建应用是有一定风险的,因为 SSR 支持仍是测试版。但我们发现,Vite 的速度非常快,很容易通过自定义选项进行扩展,而且在开发人员中相当受欢迎。我们继续通过 PR 和 bugfix 与 Vite 的核心团队合作。Shopify 也是 Vite 和 Vue.js 项目的赞助商。
了解更多:如何使用 Vite 为 Hydrogen 打造一流的开发者体验。
Tailwind
在 Unite 2021 期间的 Hydrogen 原始 demo 中,Tobi 使用 Tailwind CSS 搭建了一个 带有 3D 模型的互动产品详情页。Tailwind 简化了应用原子式 CSS 类来修改组件的外观的步骤,不必在 React 组件和 CSS 文件之间来回跳动。
Tailwind 非常受欢迎——在 2021 年的 CSS 状态调查结果中,开发人员满意度为78%——选择它作为我们的 demo 商店模板本身并不是一个巨大的赌注,但是,原子 CSS 是一种有争议的网络应用样式设计方法,我们知道不是每个人都想在 Hydrogen 应用中使用 Tailwind。然而,我们发现它在搭建和扩展大型 Hydrogen 店面方面非常高效。
了解更多:为什么 Tailwind 是建立 Hydrogen 应用程序的完美选择。
收集和执行反馈
Hydrogen 和 Oxygen 这样的项目不能在“孤岛”上搭建,搭建 Hydrogen 这样的开源项目尤其如此,它要与许多其他开源项目互动,部署到许多不同的页面。
内部合作
Shopify 是一家大公司,如果没有与不同领域的同事合作,我们不可能建立 Hydrogen。
我们内部合作的方式之一是与我们的 API 团队合作,该团队根据社区的反馈不断改进 Storefront API,包括新的购物车 API、大修模式、以及新的私人 API 令牌,来改善服务器到服务器调用的速率限制。
我们还经常与 Oxygen 团队合作,对 Hydrogen 项目的部署管道进行微调。这包括与该团队合作定义 Oxygen 运行时的要求,如通过传入请求提供对地理位置属性的访问。
Hydrogen 团队正在与 Shopify 的其他核心团队合作,为框架增加功能,包括客户认 证、搜索引擎优化(SEO)和分析。同时,我们也正在创建示例代码,以展示如何与这些 Shopify 功能集成。
在内部使用 Hydrogen 也是构建框架的一个重要部分。Shopify 的其他团队一直在自己的产品中使用 Hydrogen,比如 Linkpop 和 Shopify Supply。把 Hydrogen 放到生产场景中,帮助我们发现 API 的局限性,促进产品的改进。
业内合作
搭建 Hydrogen 也需要很多 Shopify 以外的合作,且比我预期的要多。
我们定期与 React 核心团队会面,讨论对服务器组件的探索。我们已经为新功能、错误报告和错误修复贡献了拉动请求。
我们正在继续迭代上游的服务器组件插件的 Vite 版本。
我们正在与 Vercel 合作,定义与 Next.js 一致的新服务器组件公约,确定在 Vercel 上部署 Hydrogen 应用程序的最佳方式。
我们与 Vite 核心团队进行了广泛的合作,通过 PR 来增加新的功能和修复错误。
早期,我们与 Cloudflare 在 Oxygen 上合作,并与他们一起完善了他们的 ReadableStream 实现,还加入了 WinterCG,并且已经提出了诸如标准化访问 cookie 标头和运行时变量的议题。
谷歌有一个名为 Aurora 的倡议。我们正在与他们合作,建立一个标准化的图像组件,促进在 Hydrogen 中执行最佳做法。
像 Sanity 这样的 Hydrogen 的早期第三方采用者帮助我们定义了早期的 API 模式,并 创建了 Hydrogen Sanity demo 商店这样的例子。
我们正在与 Remix 合作,创建一个 Hydrogen 堆栈,并找到在 Remix 应用程序中实现Hydrogen 组件的好方法。
我们正在与 Netlify 等其他托管平台合作,在 Oxygen 之外部署 Hydrogen。
Hydrogen 的开发人员也一直忙于参加各种会议并发表演讲和发言。Helen Lin 在 2021 年 12 月的 ReactConf 上发言,我在今年早些时候的 FSJam 播客上发言。Bret Little 与 Ryan Carniato在直播中谈到了服务器组件,Anthony Frehner 在 2022 年 RemixConf 上发表了演讲。Matt Seccafien 和 Cathryn Griffiths 在 2021 年的 React Advanced London 上主持了一个研讨会,而 Scott Dixon 在 SmashingConf 研讨会 上向开发人员讲授了 Hydrogen 和服务器组件。
请期待 Hydrogen 在播客和会议上的更多亮相!
Hydrogen 的展望
目前,Hydrogen 已经在 Allbirds、Shopify Supply、Shopify Hardware 和 Shopify 的生产中使用。Hydrogen 的 npm 包每月被下载超过 70,000 次。
未来是光明的,而我们才刚刚开始。期待看到 Hydrogen 的大量更新,包括与 Shopify 生态系统的其他部分更深入的整合,服务器组件的新设计,新的 Hydrogen 路由器,以及从现有的 Liquid 店面逐步采用 Hydrogen 的方法。
如果你还没有体验过 Hydrogen,请点击 https://hydrogen.new 体验一下,或者查看这篇精彩的文档。欢迎开发人员使用 Hydrogen,让商业惠及所有人。
更多信息
· Building Blocks of High Performance Hydrogen-powered Storefronts
· Rapid Development with Hydrogen: Building a Product Page
· Best-in-Class Developer Experience with Vite and Hydrogen
· React Server Components Best Practices You Can Use with Hydrogen
· Hydrogen & Tailwind: The Perfect Match for Building Beautiful Storefronts
如果你也喜欢从零开始搭建系统来解决现实问题,可以查看我们工程博客中的其他文章,内容是关于我们遇到其他挑战。同时,欢迎访问我们的工程职业页面,了解我们的空缺职位,我们热烈欢迎小伙伴加入我们的远程工作团队,了解我们如何通过招聘来共同设计未来——一个通过设计实现数字化的未来。
原文作者:Josh Larson
Josh Larson 是 Shopify 的高级员工开发人员,是 Hydrogen 团队的一员。他居住在爱荷华州的得梅因。工作之余,他享受与家人在一起的时光,喜欢与朋友一起玩音乐, 观看电视节目。
原文链接:How We Built Hydrogen: A React Framework for Building Custom Storefronts — Development (2022)