我们如何建造Hydrogen,构建自定义店面的React框架
我们在一年多的时间里一直在构建Hydrogen,一个用于在Shopify上构建自定义店面的React框架。我们投资了最先进的新技术,比如React服务器组件,以确保在Shopify平台上的构建对开发者来说是一个非常好的体验。
以下是我们如何做到这一点的幕后故事,我们从巨大的赌注中学到了什么,以及在实验性技术上从头开始建立一个新框架的感觉。
我们为什么建造Hydrogen
我们建立Hydrogen是为了解决商家--尤其是大型商家--所面临的问题。我如何使用Shopify的店面API来建立一个自定义的店面,而不失去我在Liquid店面中免费得到的一切?虽 然商家会得到一个完全定制的店面的好处,但他们也会面临一些问题,如选择一个框架、建立购物车和产品选择的基元、性能、测试、可访问性、托管、扩展、可观察性和分析。
在Hydrogen之前,商家只能选择其他框架,要求他们从庞大的模板开始,或者完全从头开始建立。我们相信商业本身就是动态的,我们发现面向JAMStack的框架,建立静态版本的网站,需要不断地重新构建,并不是最适合Shopify的。这就是为什么我们全力打造Hydrogen,我们的动态定制店面框架由React驱动。氢气的目的是默认为商家解决所有这些问题,加快开发时间。开发人员应该享受在一个平台上的建设,氢气是以最好的开发者体验为前提的。
迭代、发货和迭代
2021年4月1日,我们创建了一个新的空GitHub仓库,名为Shopify/hydrogen 。我们当时还不知道自己在构建什么,也绝对不知道最终的结果是什么。从那时起,我们发布了1200多个拉动请求和3000个提交,才有了你今天看到的氢气版本。
我们通过试验和错误学到了很多东西。我们认为新的组件会很有用,但当我们发现它们没有用时,就把它们删除。我们引入了新的功能,但也引入了新的错误。我们从早期采用者和正在使用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包中被掩盖了,使人很难发现正在请求什么数据。为了缓解这个问题,我们做了两件事,改善了Hydrogen的开发者体验。
首先,我们创建了一个新的实验性记录器来检测GraphQL查询中未使用的属性。当开发者请求的数据在他们的组件中没有被使用时,它就会发出警报,并鼓励他们从页面中删除这些字段以提高性能。
Hydrogen的DevTools为开发者提供了有用的提示,以提高其定制店面的速度和性能。
第二,我们从Hydrogen的npm包中删除了几乎所有的片段导出。这意味着在新上架的Hydrogen应用程序中会有更多的冗长查询,但它也使查询的数据更容易被开发者发现。它鼓励开发者根据自己的需要对查询进行微调,而不是依赖片段。
结果是巨大的:Hydrogen演示商店模板中的一些路线,其加载时间减少了一半。我们仍在试验这些工具,以及找到一种方法,以更聪明的方式引入片段,帮助刚接触GraphQL的开发者更快上手。
在公共场合构建
将Hydrogen这样的东西作为一个公共的开源项目来构建的一个好处是来自外部开发者的贡献。这方面的例子包括为useShopQuery , 防止演示商店模板中的错误,以及增加国际化支持。事实上,自2021年11月以来,Hydrogen已经接受了来自十几个外部开发者的贡献。
公开构建的另一个好处是,我们可以通过讨论和问题得到开发者的外部反馈。我们提出了我们最初的路由策略并得到了反馈,并对我们的缓存API进行了调整。我们还听说,开发者非常 希望我们在演示商店模板中使用TypeScript(所以我们就这么做了!)。
下大赌注
当我们在2021年初着手建立Hydrogen时,我们承担了风险。我们相信,随着时间的推移,我们使用的技术将继续改进,并计划从我们以前的赌注中不断学习,以便在未来做出更好的赌注。以下是我们所冒风险的几个亮点,以及它们如何将氢气变成今天的样子。
关于React服务器组件
2020年12月,React宣布了React服务器组件(RSC),这是一个仍在开发中的功能,将使React组件在服务器上渲染,而不需要客户端的JavaScript,从而使页面渲染更快。快进到2021年4月,当时我们正在考虑在Hydrogen中建立什么样的数据获取API。
在我们的Slack频道中,我们感叹RSC模式是理想的,不幸的是它还没有发布。
所以我们没有等待,而是决定建立一个能在Vite中运行的版本,并立即开始使用它。我们天真地实现了(基于一些逆向工程)飞行语法 ,将React组件序列化,并使它们在浏览器中互动。
2021年5月在我们的私有氢气库中切换到服务器组件的PR截图,然后我们在2021年11月随着开发者预览版的推出切换到公共库。
这种天真的实施方式使我们能够推动建立一个基于服务器组件的框架,并支持组件级的数据获取等,而不是等待数月或数年后服务器组件的最终生产版本才能实现。
我们最终转向了由React内部飞行语法驱动的官方版本的服务器组件。
RSC是我们今天在氢气上所做的最大的技术赌注。我们相信它提供了客户端和服务器组件之间的完美分离。从第一方和第三方代码库中混合和匹配服务器组件的能力创造了一种模块化,这是其他框架所无法比拟的。不可能将一个在服务器上获取数据的组件放到一个非RSC框架中,因为其他框架要求数据获取发生在路由层。有了RSC,服务器组件可以被添加到Hydrogen应用程序中,并且可以开箱即用。第三方开发者是Shopify生态系统的生命线,所以这对Hydrogen来说非常有意义。
Hydrogen提供工具来帮助开发者使用React服务器组件来支持他们的定制店面。
我们正在与Meta的React核心团队和Vercel的Next.js团队密切合作,迭代和完善服务器组件的设计。我们已经对服务器组件中提出的服务器模块惯例进行了反馈,我们正在努力寻找一个对所有开发者都最有效的API。氢气和Next.js将在我们解决最后的细节问题时保持对服务器组件API规范的关注。
我们也认识到,教育是采用的关键,所以我们已经在Hydrogen的背景下编写了关于服务器组件的文档。我们将继续改进我们的文档,以帮助社区在未来几个月内采用服务器组件。
关于Vite
直到一年前,webpack一直是大多数前端项目的首选捆绑器。它是一个很好的工具,但我们决定用Vite作为Hydrogen的捆绑器。
在Vite上构建是有一定风险的,因为SSR支持仍然被认为是测试版。然而,我们发现,Vite的速度非常快,很容易用自定义选项进行扩展,而且在开发者中相当受欢迎。我们继续通过PR和错误修复与Vite的核心团队合作。Shopify也是Vite和Vue.js项目的财务赞助商。
阅读更多关于我们如何使用Vite为Hydrogen打造一流的开发者体验。
关于Tailwind
在Unite 2021期间的Hydrogen原始演示中,Tobi使用Tailwind CSS建立了一个带有3D模型的互动产品详情页。Tailwind使得应用原子CSS类来修改组件的外观变得很容易,而不必在React组件和CSS文件之间来回跳跃。
Tailwind非常受欢迎--在 2021年的CSS状态调查结果中,它在开发者满意度方面排名78%--为我们的演示商店模板挑选它本身并不是一个巨大的赌注。但是,原子CSS是一种有争议的网络应用样式设计方法,我们知道不是每个人都想在氢气应用中使用Tailwind。然而,我们发现它对于建立和扩展大型氢气店面来说是非常有效和高效的。
阅读更多关于为什么Tailwind是构建Hydrogen应用程序的完美选择。
收集和实施反馈
像Hydrogen和Oxygen这样的项目并不是在一个筒子里建立的。当建立像Hydrogen这样的开源项目时尤其如此,它与许多其他开源项目互动,并被部署到许多不同的表面。
内部协作
Shopify是一家大公司,如果没有与在公司不同领域工作的Shopifolk同事合作,我们不可能建立氢气。
我们内部合作的方式之一是与我们的API团队合作,该团队根据社区的反馈不断改进Storefront API。这包括一个新的购物车API,一个经过整改的模式,以及一个新的私人API令牌,以改善服务器到服务器调用的速率限制。
我们还经常与Oxygen团队合作,对Hydrogen项目的部署管道进行微调。这包括与该团队合作定义对Oxygen运行时的要求,如通过传入请求提供对地理位置属性的访问。
氢气团队正在与其他核心Shopify团队合作,为框架添加功能,包括客户认证、搜索引擎优化(SEO)和分析。我们还在创建示例代码,以演示如何与这些Shopify功能集成。
在内部推广氢气也是构建框架的一个重要部分。Shopify的其他团队已经在他们自己的产品中使用Hydrogen,比如Linkpop和Shopify Supply。将Hydrogen放到生产场景中帮助我们发现我们的API的局限性,从而进行改进。
与行业合作
建立Hydrogen导致了Shopify以外的 合作,这比我想象的要多。
我们定期与React核心团队会面,讨论我们对服务器组件的探索。我们为新功能、错误报告和错误 修复提供了拉动请求。
我们正在继续迭代上游的服务器组件插件的Vite版本 。
我们正在与Vercel合作,定义与Next.js一致的新服务器组件约定,并确定在Vercel上部署Hydrogen应用程序的最佳方式。
我们与Vite核心团队进行了广泛的合作,通过PR增加新的功能和修复错误。
早期,我们与Cloudflare在Oxygen上合作,并与他们一起完善了他们的ReadableStream 实现。我们还加入了WinterCG,并且已经提出了诸如标准化访问cookie头和运行时变量的议题。
谷歌有一个名为Aurora的倡议。我们正在与他们合作,建立一个标准化的Image 组件,并从一开始就在Hydrogen中执行最佳实践。
像Sanity这样的Hydrogen的早期第三方采用者帮助我们定义早期的API模式,并创建了Hydrogen Sanity演示商店这样的例子。
我们正在与Remix合作,创建Hydrogen Stack,并找到在Remix应用中实施Hydrogen组件的好方法。
我们正在与Netlify等其他托管平台合作,在Oxygen之外部署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已经在Allbirds、Shopify Supply、Shopify Hardware和Shopify本身的生产中使用。氢气的npm包每月被下载超过70,000次。
未来是光明的,我们才刚刚开始。期待看到Hydrogen的大量更新,包括与Shopify生态系统的其他部分更深入的整合,服务器组件的新设计,新的Hydrogen路由器,以及从现有的液体店面逐步采用Hydrogen的方法。
如果你还没有,请在hydrogen.new,体验一下Hydrogen,或者查看一下精彩的文档。我们很高兴看到开发者使用Hydrogen,使商务对每个人都有好处。