- CLI
- 后端
- 云原生
【免费下载链接】vercel
Develop. Preview. Ship.
导读
@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-config(workspace:*工作区依赖)读取 Hydrogen 配置,通过ts-morph解析 TypeScript 中的配置导出; - 以
@vercel/build-utils为开发依赖,复用其download、glob、EdgeFunction、runNpmInstall等 Builder 基础设施。
在框架自动检测层面,packages/frameworks/src/frameworks.ts 中注册了hydrogen框架条目:通过检测依赖@shopify/hydrogen或hydrogen.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 协议版本)、build与prepareCache。核心构建逻辑集中在 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(包管理器类型)、lockfilePath、lockfileVersion、packageJsonPackageManager(corepackpackageManager字段)以及turboSupportsCorepackHome(当前 Turborepo 是否支持COREPACK_HOME),再由getEnvForPackageManager生成适合该包管理器的子进程环境。这套逻辑正是 CHANGELOG 中 1.0.3~1.0.9 反复迭代的 "corepackpackageManager检测" 相关变更的实际落点:corepack 需要依赖正确的COREPACK_HOME与packageManager字段才能在 monorepo 场景下选择正确的包管理器版本。
2.3 安装与构建命令的选择
安装阶段遵循 Builder 常规约定:
- 若
config.installCommand为字符串且非空,则直接执行该命令,否则记录Skipping "install" command...; - 未显式配置时调用
runNpmInstall,使用探测出的包管理器环境执行安装。
构建阶段("Build Command")依次尝试:
- 显式配置的
buildCommand; package.json中的vercel-build脚本;package.json中的build脚本;- 兜底执行
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模板本身做了三件事:
- 从
__RELATIVE__/src/App.server引入 Hydrogen 应用入口; - 从
__RELATIVE__/dist/client/index.html?raw引入客户端 HTML 模板; - 用
web-streams-polyfill/ponyfill的ReadableStream覆盖全局实现,注释明确说明 "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.0 | Major | 破坏性变更:放弃 Node.js 14,最低要求提升到 Node.js 16 | getNodeVersion选择运行时版本 |
| 1.0.1 | Patch | 改用build-builder.mjs脚本打包,移除类型声明与 source map | package.json 中"build": "node ../../utils/build-builder.mjs" |
| 1.0.2 | Patch | 弃用EdgeFunction#name属性 | EdgeFunction通过deploymentTarget/entrypoint描述 |
| 1.0.3~1.0.9 | Patch | corepackpackageManager检测的多次修复、回退与重试(涉及 #11811、#11865、#11871、#12099、#12211、#12219、#12242、#12258) | scanParentDirs+getEnvForPackageManager的 corepack 分支 |
| 1.1.0 | Minor | 将.yarn/cache纳入构建缓存 | defaultCachePathGlob |
| 1.2.0 | Minor | 新项目将 v9 pnpm lockfile 识别为 pnpm 10 | lockfileVersion 探测逻辑 |
| 1.2.3 | Patch | 回退对preferredRegion的支持 | regions改由 Hydrogen 静态配置解析 |
| 1.3.0 | Minor | 通过 vercel.json 属性支持 Bun | getEnvForPackageManager的 Bun 分支 |
| 1.3.1 / 1.3.2 / 1.3.5 | Patch | getSpawnOptions的移除、回退、再次移除(#14176、#14261、#14604) | 子进程环境统一收敛到getEnvForPackageManager |
| 1.3.3 | Patch | 工作区依赖改用workspace:*协议 | package.json 中@vercel/static-config: "workspace:*" |
| 1.3.4 | Patch | 用getRuntimeNodeVersion替换getNodeVersion(#14600) | getNodeVersion调用点 |
| 1.3.6~1.3.8 | Patch | @vercel/static-config依赖升级(3.1.x → 3.4.0) | 静态配置解析能力随依赖演进 |
| 1.4.0 | Minor | 为 node 前端构建器添加 project manifest | generateProjectManifest调用 |
其中值得展开的是1.4.0 的 project manifest:构建器在安装后调用generateProjectManifest,写入包含nodeVersion、cliType、lockfilePath、lockfileVersion、framework、serviceType的清单文件;失败时仅记录 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)使用useShopQuery、useServerAnalytics、Seo、CacheLong等 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=worker与SHOPIFY_FLAG_BUILD_SSR_ENTRY→ 执行 Hydrogen 构建 → 收集dist/client与dist/worker→ 组装 v8-worker Edge Function 与静态文件路由——为理解 Vercel Builder 协议提供了一个完整、可读性极高的范本。如果你需要为其他 SSR 框架编写类似的 Vercel 构建适配层,build.ts 与 edge-entry.js 是最直接的参考实现。
- CLI
- 后端
- 云原生
【免费下载链接】vercel
Develop. Preview. Ship.
相关推荐
Hydrogen 定制店面实战:基于 Vercel 示例仓库的 Shopify Hydrogen 框架上手指南
Hydrogen 定制店面实战:基于 Vercel 示例仓库的 Shopify Hydrogen 框架上手指南 Hydrogen 是 Shopify 官方推出的
示例工程前端后端Hydrogen v2 + Remix 模板的 Vercel 零配置部署指南(Shopify 无头电商实战)
Hydrogen v2 + Remix 模板的 Vercel 零配置部署指南(Shopify 无头电商实战) 本文基于 Vercel 官方仓库 examples
CLI后端云原生Hydrogen v2 无头电商模板实战指南:基于 Remix 的 Shopify 店铺从零部署到 Vercel
Hydrogen v2 无头电商模板实战指南:基于 Remix 的 Shopify 店铺从零部署到 Vercel 导读 本文围绕仓库 framework boi
示例工程前端后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考