@vercel/hydrogen 构建器深度解析:Shopify Hydrogen 在 Vercel 上的部署演进与源码实现
2026/9/23 2:43:51 网站建设 项目流程
  • CLI
  • 后端
  • 云原生

【免费下载链接】vercel

Develop. Preview. Ship.

项目地址:https://gitcode.com/gh_mirrors/ve/vercel
点击查看免费下载

导读

@vercel/hydrogen是 Vercel 官方仓库(monorepo)中负责构建 Shopify Hydrogen 应用的部署构建器(Builder),它把 Hydrogen 的 Vite 应用转换为可在 Vercel Edge Network 上运行的 Edge Function 与静态资源组合。本文以 packages/hydrogen/CHANGELOG.md 的版本演进为主线,结合 packages/hydrogen/src/build.ts、packages/hydrogen/src/prepare-cache.ts 等源码与测试夹具,讲清该构建器的工作原理、缓存机制、包管理器探测逻辑,以及 1.0.0 到 1.4.0 之间每一次关键变更背后的技术动因。读完你将掌握 Hydrogen 应用在 Vercel 上的完整构建链路,并能从源码层面理解 Builder 的扩展方式。

一、@vercel/hydrogen 在仓库中的定位

@vercel/hydrogen是 Vercel 部署平台为 Shopify 官方 React 无头电商框架 Hydrogen 提供的构建适配层,位于仓库 packages/hydrogen 目录。从 package.json 可以看到它的本质:

  • 包名@vercel/hydrogen,当前版本1.4.0,License 为 Apache-2.0;
  • 通过@vercel/static-configworkspace:*工作区依赖)读取 Hydrogen 配置,通过ts-morph解析 TypeScript 中的配置导出;
  • @vercel/build-utils为开发依赖,复用其downloadglobEdgeFunctionrunNpmInstall等 Builder 基础设施。

在框架自动检测层面,packages/frameworks/src/frameworks.ts 中注册了hydrogen框架条目:通过检测依赖@shopify/hydrogenhydrogen.config.js/hydrogen.config.ts文件来识别 Hydrogen 项目,并绑定useRuntime: { src: 'package.json', use: '@vercel/hydrogen' },即当项目被识别为 Hydrogen 后,部署时将使用@vercel/hydrogen作为构建器,同时预设shopify hydrogen build为构建命令、dist为输出目录、PUBLIC_为环境变量前缀。

二、构建流程源码级解析

@vercel/hydrogen的入口在 packages/hydrogen/src/index.ts,导出version = 2(Builder 协议版本)、buildprepareCache。核心构建逻辑集中在 build.ts。

2.1 环境准备:PUBLIC_ 前缀环境变量

构建的第一步是下载用户文件并把带PUBLIC_前缀的环境变量注入构建进程:

const prefixedEnvs = getPrefixedEnvVars({ envPrefix: 'PUBLIC_', envs: process.env, }); for (const [key, value] of Object.entries(prefixedEnvs)) { process.env[key] = value; }

这与框架配置中的envPrefix: 'PUBLIC_'一致:Hydrogen 遵循 Vite 的import.meta.env约定,构建期会把PUBLIC_*变量嵌入客户端代码。

2.2 Node 版本与包管理器探测

构建器先确定 Node 运行时版本:

const nodeVersion = await getNodeVersion(entrypointDir, undefined, config, meta);

随后通过scanParentDirs沿目录向上扫描,收集cliType(包管理器类型)、lockfilePathlockfileVersionpackageJsonPackageManager(corepackpackageManager字段)以及turboSupportsCorepackHome(当前 Turborepo 是否支持COREPACK_HOME),再由getEnvForPackageManager生成适合该包管理器的子进程环境。这套逻辑正是 CHANGELOG 中 1.0.3~1.0.9 反复迭代的 "corepackpackageManager检测" 相关变更的实际落点:corepack 需要依赖正确的COREPACK_HOMEpackageManager字段才能在 monorepo 场景下选择正确的包管理器版本。

2.3 安装与构建命令的选择

安装阶段遵循 Builder 常规约定:

  • config.installCommand为字符串且非空,则直接执行该命令,否则记录Skipping "install" command...
  • 未显式配置时调用runNpmInstall,使用探测出的包管理器环境执行安装。

构建阶段("Build Command")依次尝试:

  1. 显式配置的buildCommand
  2. package.json中的vercel-build脚本;
  3. package.json中的build脚本;
  4. 兜底执行shopify hydrogen build

测试夹具(如 demo-store-ts/package.json)均以shopify hydrogen build作为构建脚本,与兜底逻辑互为印证。

2.4 Edge Function 打包的关键:两个 SHOPIFY_FLAG 环境变量

这是构建器最核心的魔术所在。构建器先把 edge-entry.js 模板复制到.vercel/cache/hydrogen/edge-entry.js,并用构建目录到工作目录的相对路径替换其中的__RELATIVE__占位符:

edgeEntryContents = edgeEntryContents.replace(/__RELATIVE__/g, edgeEntryRelative);

edge-entry.js模板本身做了三件事:

  1. __RELATIVE__/src/App.server引入 Hydrogen 应用入口;
  2. __RELATIVE__/dist/client/index.html?raw引入客户端 HTML 模板;
  3. web-streams-polyfill/ponyfillReadableStream覆盖全局实现,注释明确说明 "ReadableStream is bugged in Vercel Edge"(Vercel Edge 环境的流实现存在缺陷,需 polyfill)。

随后构建器设置两个关键环境变量并执行构建命令:

spawnEnv.SHOPIFY_FLAG_BUILD_TARGET = 'worker'; spawnEnv.SHOPIFY_FLAG_BUILD_SSR_ENTRY = edgeEntryDest;

即要求shopify hydrogen build产出worker 目标的 SSR 包,并以注入后的 edge-entry 作为 SSR 入口。构建完成后从dist/client收集静态文件、从dist/worker收集 Edge Function 文件。

2.5 产物组装与路由

const edgeFunction = new EdgeFunction({ deploymentTarget: 'v8-worker', entrypoint: 'index.js', files: edgeFunctionFiles, regions: (() => { // 通过 ts-morph + @vercel/static-config 解析 dist/worker/index.js 中的 regions 配置 })(), });

其中regions通过Project(ts-morph)解析 worker bundle 中的静态配置导出得到——这正是@vercel/static-config依赖的用途。对应 CHANGELOG 1.2.3 "Reverting support forpreferredRegion" 可推断:早期版本曾尝试支持该配置,后因故回退,最终形态是支持从 Hydrogen 静态配置读取regions

最终输出包含路由规则:

routes: [ { handle: 'filesystem' }, { src: '/(.*)', dest: '/hydrogen' }, ]

即先匹配静态文件系统(dist/client下除index.html外的所有资源),其余请求全部交给名为hydrogen的 Edge Function 做 SSR 渲染——注意delete staticFiles['index.html'],因为该文件只是模板,实际应返回 SSR 版本。

三、构建缓存机制

prepare-cache.ts 的实现极其简洁:

export const prepareCache: PrepareCache = ({ repoRootPath, workPath }) => { return glob(defaultCachePathGlob, repoRootPath || workPath); };

缓存路径模式定义于 packages/build-utils/src/default-cache-path-glob.ts:

export const defaultCachePathGlob = '**/{node_modules,.yarn/cache}/**';

即默认缓存node_modules.yarn/cache两个目录,使依赖在多次部署间复用,加快构建。CHANGELOG 中 1.1.0 "Add .yarn/cache to build cache" 正是把 Yarn 的零安装依赖缓存纳入该模式的变更;而 1.2.0 "Detect v9 pnpm lock files as pnpm 10 for new projects" 则是把新版 pnpm(lockfile v9 对应 pnpm 10)正确识别为 pnpm 10 的探测修正,与构建阶段scanParentDirs的 lockfile 版本探测直接相关。

四、版本演进史:从 1.0.0 到 1.4.0 的关键变更

以下按 CHANGELOG 时间线梳理影响构建行为的关键变更(PR 编号以原文记录为准,此处仅列文字便于检索):

版本类型变更内容源码印证
1.0.0Major破坏性变更:放弃 Node.js 14,最低要求提升到 Node.js 16getNodeVersion选择运行时版本
1.0.1Patch改用build-builder.mjs脚本打包,移除类型声明与 source mappackage.json 中"build": "node ../../utils/build-builder.mjs"
1.0.2Patch弃用EdgeFunction#name属性EdgeFunction通过deploymentTarget/entrypoint描述
1.0.3~1.0.9PatchcorepackpackageManager检测的多次修复、回退与重试(涉及 #11811、#11865、#11871、#12099、#12211、#12219、#12242、#12258)scanParentDirs+getEnvForPackageManager的 corepack 分支
1.1.0Minor.yarn/cache纳入构建缓存defaultCachePathGlob
1.2.0Minor新项目将 v9 pnpm lockfile 识别为 pnpm 10lockfileVersion 探测逻辑
1.2.3Patch回退对preferredRegion的支持regions改由 Hydrogen 静态配置解析
1.3.0Minor通过 vercel.json 属性支持 BungetEnvForPackageManager的 Bun 分支
1.3.1 / 1.3.2 / 1.3.5PatchgetSpawnOptions的移除、回退、再次移除(#14176、#14261、#14604)子进程环境统一收敛到getEnvForPackageManager
1.3.3Patch工作区依赖改用workspace:*协议package.json 中@vercel/static-config: "workspace:*"
1.3.4PatchgetRuntimeNodeVersion替换getNodeVersion(#14600)getNodeVersion调用点
1.3.6~1.3.8Patch@vercel/static-config依赖升级(3.1.x → 3.4.0)静态配置解析能力随依赖演进
1.4.0Minor为 node 前端构建器添加 project manifestgenerateProjectManifest调用

其中值得展开的是1.4.0 的 project manifest:构建器在安装后调用generateProjectManifest,写入包含nodeVersioncliTypelockfilePathlockfileVersionframeworkserviceType的清单文件;失败时仅记录 debug 日志而不中断构建,体现了"清单为增强信息、构建为硬约束"的设计取舍。

五、测试与验证:真实部署夹具

测试入口 packages/hydrogen/test/test.js 遍历fixtures目录下每个夹具,调用testDeployment发起真实部署并校验探针(probe)响应,超时上限设为 12 分钟:

vi.setConfig({ testTimeout: 12 * 60 * 1000, hookTimeout: 12 * 60 * 1000 }); for (const fixture of fs.readdirSync(fixturesPath)) { it.concurrent(`should build ${fixture}`, async () => { await expect(testDeployment(...)).resolves.toBeDefined(); }); }

夹具共四套,覆盖 JS/TS 与简繁两种形态:

  • hello-world-js 与 hello-world-ts:最小示例,探针校验首页包含 "Hello World";
  • demo-store-js 与 demo-store-ts:完整的 Hydrogen demo store,探针校验首页渲染 Shopify 店铺数据、404 页正常。

每个夹具的 vercel.json 展示了 Builder 的标准接入方式:

{ "version": 2, "builds": [ { "src": "package.json", "use": "@vercel/hydrogen", "config": { "zeroConfig": true } } ], "probes": [ { "path": "/", "mustContain": "All Mountain All Season" } ] }

zeroConfig: true表示完全依赖框架默认设置;probes是部署后的断言探针,确保 SSR 输出与 404 路由符合预期。

六、Hydrogen 应用自身的配置形态

从 demo-store-ts/hydrogen.config.ts 可看到 Hydrogen 应用侧的配置形态,这也是构建器通过@vercel/static-config读取的配置来源:

import {defineConfig, CookieSessionStorage} from '@shopify/hydrogen/config'; export default defineConfig({ shopify: { defaultCountryCode: 'US', defaultLanguageCode: 'EN', storeDomain: 'hydrogen-preview.myshopify.com', storefrontToken: '3b580e70970c4528da70c98e097c2fa0', storefrontApiVersion: '2022-07', }, session: CookieSessionStorage('__session', { path: '/', httpOnly: true, secure: import.meta.env.PROD, sameSite: 'Strict', maxAge: 60 * 60 * 24 * 30, }), });

而应用路由层(如 index.server.tsx)使用useShopQueryuseServerAnalyticsSeoCacheLong等 Hydrogen 服务端 API 拉取 Storefront GraphQL 数据并输出 SSR 内容,最终由@vercel/hydrogen打包的 Edge Function 在 Vercel Edge Network 上执行。这也解释了为何部署后首页探针能直接断言店铺文案——内容在边缘端实时渲染而非静态缓存。

七、总结

从版本史看,@vercel/hydrogen的演进始终围绕三件事:更准确的依赖与运行时探测(corepack、pnpm 10、Bun、Node 16+)、更稳定的构建环境.yarn/cache缓存、getSpawnOptions的移除与收敛)、更完备的部署元数据(project manifest、regions 支持)。其核心构建链路——下载源码 → 注入PUBLIC_*变量 → 探测 Node 与包管理器 → 安装依赖 → 注入SHOPIFY_FLAG_BUILD_TARGET=workerSHOPIFY_FLAG_BUILD_SSR_ENTRY→ 执行 Hydrogen 构建 → 收集dist/clientdist/worker→ 组装 v8-worker Edge Function 与静态文件路由——为理解 Vercel Builder 协议提供了一个完整、可读性极高的范本。如果你需要为其他 SSR 框架编写类似的 Vercel 构建适配层,build.ts 与 edge-entry.js 是最直接的参考实现。

  • CLI
  • 后端
  • 云原生

【免费下载链接】vercel

Develop. Preview. Ship.

项目地址:https://gitcode.com/gh_mirrors/ve/vercel
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询