免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

使用 Hypertune 与 Flags SDK 在 Next.js 中构建可覆盖的功能开关(附 Flags Explorer 联调指南)

使用 Hypertune 与 Flags SDK 在 Next.js 中构建可覆盖的功能开关(附 Flags Explorer 联调指南) 使用 Hypertune 与 Flags SDK 在 Next.js 中构建可覆盖的功能开关附 Flags Explorer 联调指南【免费下载链接】examplesEnjoy our curated collection of examples and solutions. Use these patterns to build your own robust and scalable applications.项目地址: https://gitcode.com/GitHub_Trending/examples1/examples本文以仓库中flags-sdk/hypertune示例为主线系统讲解如何将 Hypertune 作为托管功能开关平台通过 Vercel Flags SDK 的模板适配器接入 Next.js 应用并打通 Flags Explorer 的本地覆盖调试能力。读完本文你将掌握从 Schema 设计、Logic 分流配置、本地部署联调到源码级理解稳定 ID、预计算重写precompute/rewrite与按组合静态生成ISR的完整链路可直接照搬到自己的 Next.js 项目中。示例概览一个双 Banner 实验型电商页面该示例模拟了一个电商商品详情页与购物车流程核心实验是首页上两条横幅Banner的显示组合Summer Sale夏季促销与Free Delivery免运费两条横幅各自被配置为50% 概率显示、50% 概率隐藏。因此每次访问页面时用户会看到四种组合中的一种两条横幅都显示只显示其中一条两条都不显示。示例通过**稳定 IDstable id**来标识用户同一稳定 ID 的用户在 ID 被重置之前会一直看到同一变体。页面右下角内置了 Dev Tools 面板点击 Reset Stable ID 按钮即可重置稳定 ID 并刷新页面从而快速遍历不同的横幅组合。若将示例克隆到本地还可以通过 Flags Explorer 创建覆盖override来测试任意变体——这正是 Flags SDK 与 Hypertune 集成的核心价值远程托管开关 本地/平台侧可视化覆盖。从目录结构看页面主体在 app/[code]/page.tsx 与 app/[code]/layout.tsx使用[code]动态段承载旗帜组合编码旗帜声明集中在 flags.tsHypertune 相关适配逻辑在 template-adapter.ts 与 proxy.ts用户上下文构造在 lib/identify.ts。技术架构Flags SDK Hypertune 模板适配器本示例采用 Flags SDK依赖声明见 package.json核心依赖为flags^4.0.0、hypertune^2.7.2与flags-sdk/hypertune^0.3.0提供的模板适配器接入 Hypertune。Flags SDK 的适配器抽象了旗帜声明与决策来源之间的耦合应用代码只依赖统一的flag()声明与await flagName()调用而具体决策由适配器转发给 Hypertune。入口文件 flags.ts 展示了这一集成方式// Generated with npx hypertune import { createSource, vercelFlagDefinitions, flagFallbacks, type FlagValues, type Context, } from ./generated/hypertune import { flag } from flags/next import { createHypertuneAdapter } from flags-sdk/hypertune import { identify } from ./lib/identify const hypertuneAdapter createHypertuneAdapterFlagValues, Context({ createSource, flagDefinitions: vercelFlagDefinitions, flagFallbacks, identify, }) export const showSummerBannerFlag flag( hypertuneAdapter.declarations.summerSale ) export const showFreeDeliveryBannerFlag flag( hypertuneAdapter.declarations.freeDelivery ) export const proceedToCheckoutColorFlag flag( hypertuneAdapter.declarations.proceedToCheckout ) export const delayFlag flag({ ...hypertuneAdapter.declarations.delay, options: [ { value: 0, label: No delay }, { value: 1_000, label: 1 second }, { value: 2_000, label: 2 seconds }, { value: 3_000, label: 3 seconds }, ], }) export const productFlags [ showFreeDeliveryBannerFlag, showSummerBannerFlag, proceedToCheckoutColorFlag, ] as const关键点拆解createHypertuneAdapter由flags-sdk/hypertune提供的工厂函数接收四个参数——createSource构造 Hypertune 查询节点、vercelFlagDefinitionsFlag Explorer 所需的旗帜元数据含选项与来源链接、flagFallbacks每个旗帜的兜底默认值、identify构造决策上下文hypertuneAdapter.declarations.*把 Hypertune 项目中定义的每个字段summerSale、freeDelivery、proceedToCheckout、delay自动提升为符合 Flags SDK 规范的旗帜声明delayFlag二次定制在继承声明的基础上为 Number 类型的delay旗帜补充了四个可读选项0/1 秒/2 秒/3 秒便于 Flags Explorer 与 Dev Tools 展示下拉选项而真正的数值由 Hypertune 返回productFlags聚合参与页面级预计算的旗帜集合供precompute/generatePermutations使用。以上createSource、vercelFlagDefinitions、flagFallbacks、FlagValues、Context均来自npx hypertune自动生成的代码文件 generated/hypertune.ts。该文件会依据你在 Hypertune 控制台定义的 Schema 自动同步包含GraphQL 查询代码queryCode与类型安全的query对象vercelFlagDefinitions每个旗帜的选项列表如proceedToCheckout的blue/red/greenfreeDelivery与summerSale的On/Off及指向 Hypertune Logic 视图的origin链接flagFallbacks与sourceFallback全部旗帜的兜底值delay: 0、proceedToCheckout: blue、freeDelivery: false、summerSale: false保证 Hypertune 不可用时应用仍可降级运行类型安全的RootNode/SourceNode节点类以及delay()、proceedToCheckout()、freeDelivery()、summerSale()等强类型取值方法。部署到 Vercel三步完成本地联调要启用 Flags Explorer 的本地覆盖能力需要完成项目关联与环境变量拉取。若在 Vercel 上直接使用 Deploy with Vercel 克隆部署会要求配置FLAGS_SECRET环境变量——它是 Flags Explorer 安全覆盖功能开关时使用的密钥必须是 32 字节随机数经 base64 编码后的值可用openssl rand -base64 32生成。部署后按以下步骤在本地打通第一步关联项目在本地执行vercel link从列表中选择刚刚部署的项目从而让本地 CLI 与远端项目建立映射。第二步拉取全部环境变量vercel env pull这会把远端的环境变量包括FLAGS_SECRET以及 Flags Explorer 所需的附加元数据拉取到本地确保 Flags SDK 与 Flags Explorer 在本地开发环境中也能正常工作。第三步配置 Hypertune在 Hypertune 控制台完成 Schema 与 Logic 的配置详见下文两节即可在本地pnpm dev启动应用体验完整的远程托管开关 本地覆盖调试闭环。配置 Hypertune一Schema 设计Hypertune 以 GraphQL 语法描述你的功能开关字段空间。示例要求在 Hypertune 控制台的Schema 标签页粘贴以下 Schema This Context input type is used for the context argument on your root field. It contains details of the current user and environment. You can define other custom input types with fields that are primitives, enums or other input types. input Context { stableId: String! environment: Environment! } type Root { delay: Int! proceedToCheckout: ProceedToCheckout! freeDelivery: Boolean! summerSale: Boolean! } enum Environment { development production test } enum ProceedToCheckout { blue red green }设计要点Contextinput 类型是根字段root的context参数类型承载当前user与environment信息。由于所有旗帜都嵌套在root字段之下这个上下文对全部旗帜全局可见可在 Logic 视图中作为分流条件使用。stableId用于把决策稳定地绑定到某个用户environment用于区分开发/生产/测试环境Root类型定义了四个字段对应四个旗帜delay: Int!——Number 类型旗帜模拟结算接口的人工延迟proceedToCheckout: ProceedToCheckout!——枚举类型旗帜控制结算按钮颜色freeDelivery: Boolean!与summerSale: Boolean!——布尔类型旗帜控制两条横幅的显示枚举Environment的取值development/production/test与ProceedToCheckout的取值blue/red/green会被代码生成器转换为 TypeScript 联合类型。在 generated/hypertune.ts 中可以看到对应产物EnvironmentEnumValues、ProceedToCheckoutEnumValues以及类型别名Environment、ProceedToCheckout。从生成的代码注释可以进一步理解 Hypertune 的字段类型设计用Boolean字段表达二态旗帜用自定义enum表达多态旗帜用Int表达数值型旗帜如超时、限额用String管理应用内文案用Void表达埋点事件还可用自定义对象/列表类型承载更复杂的应用配置此时 Hypertune 相当于一个 CMS。配置 Hypertune二Logic 分流逻辑Schema 只定义了有哪些字段真正决定用户看到什么变体的是 Logic 视图中的分流逻辑。示例要求做两件事为delay旗帜创建 Flag并将其Type 设置为 Number——这样它就是一个可返回数值的旗帜而非布尔开关为每个旗帜创建一个 Test在 Test 中按流量比例traffic切分用户并为每个分支选择与该旗帜类型匹配的取值。换句话说示例为delay、proceedToCheckout、freeDelivery、summerSale各创建了一个按百分比分流的 Test。以两条横幅为例各 Test 把流量 50/50 切分为显示 / 隐藏这正是 README 所述两条横幅各自 50% 概率出现的配置来源。旗帜名称必须与 flags.ts 中使用的声明保持一致即delay、proceedToCheckout、freeDelivery、summerSale。配置完成后npx hypertune生成的vercelFlagDefinitions中origin字段会指向 Hypertune 控制台中对应字段的 Logic 编辑地址方便 Flags Explorer 中跳转到 Logic 定义处的溯源。源码级原理模板适配器与确定性分流算法模板适配器template-adapter.ts是本示例教学价值最高的部分之一它用约 30 行代码实现了 Flags SDK 适配器的最小可用形态让你理解适配器到底在做什么。核心是两种决策原语rollout: (percent: number) ({ async decide({ key, entities }) { const bucket xxHash32(${entities?.visitor.id}${key}) const result bucket % 100 percent return result }, }), multivariant: (variants) ({ async decide({ key, entities }) { const bucket xxHash32(${entities?.visitor.id}${key}) % variants.length const result variants[bucket] ?? variants[0] return result }, }),rollout(percent)按百分比返回布尔结果。将visitor.id与旗帜key拼接后做xxHash32哈希再对 100 取模若小于给定百分比则命中。由于哈希是确定性的同一visitor.id 同一旗帜永远落在同一个桶中——这就是稳定 ID 用户看到稳定变体的底层保证multivariant(variants)在多个变体间均匀分配。对变体数量取模得到桶下标返回对应变体越界时回退到第一个变体。值得强调的是模板适配器只是教学用的占位实现文件头部注释明确指出——在使用真实适配器构建新示例时可以删除此文件并替换为你自己的适配器。本例真正的生产路径是flags-sdk/hypertune提供的createHypertuneAdapter它内部会把决策请求转发给 Hypertune 的云端引擎模板适配器则用于帮助你理解decide({ key, entities })的契约以及确定性哈希 取模分桶这一通用分流思想。单例缓存getTemplateAdapter避免重复创建适配器实例。稳定 ID 与用户上下文决策如何粘住同一个用户要让分流结果对同一用户保持稳定需要可复现的上下文。示例通过 lib/get-stable-id.ts 构造稳定 IDexport const getStableId: () Promisestring dedupe(async () { const [cookiesStore, headersStore] await Promise.all([cookies(), headers()]) const nonce cookiesStore.get(nonce)?.value ?? 0 const group headersStore.get(x-vercel-ip-city) ?? city const date new Date().toISOString().substring(0, 10) return Math.abs(xxHash32(${nonce}-${group}-${date})).toString(36) })稳定 ID 由三部分哈希而成nonceCookie 中的随机数默认0、x-vercel-ip-cityVercel 注入的城市头作为分组维度、当天日期YYYY-MM-DD保证决策按天轮换。dedupe来自flags/next确保同一请求周期内只计算一次。随后 lib/identify.ts 把稳定 ID 与运行环境组装成 Hypertune 决策所需的完整Contextexport const identify: IdentifyContext dedupe(async () { const stableId await getStableId() const environment process.env.VERCEL_ENV ?? process.env.NODE_ENV ?? development return { stableId, environment: environment as development | production | test, } })环境优先级为VERCEL_ENVVercel 部署环境→NODE_ENV→ 兜底development与 Schema 中Environment枚举的三个取值严格对应。Dev Tools 重置机制components/dev-tools.tsx正是围绕nonce设计的点击 Reset Stable ID 会生成新的随机数写入nonceCookie 并调用router.refresh()稳定 ID 随之变化从而在无需修改任何 Hypertune 配置的情况下遍历所有变体组合——这比在 Hypertune 控制台反复改流量比例高效得多。按组合预计算proxy 重写 静态生成 ISR旗帜数量一旦变多组合数会指数增长。Flags SDK 的推荐做法是先预计算所有旗帜的组合编码再按编码路由渲染。本示例的完整链路如下代理层预计算proxy.tsproxy中间件matcher匹配/与/cart调用precompute(productFlags)得到当前上下文下的旗帜组合编码code然后通过NextResponse.rewrite把请求重写到/${code}${pathname}。同时这里处理了首次访问场景由于第一次请求的 Cookie 头里还没有cart-id代理会为请求附加x-generated-cart-id头用 lib/get-cart-id.ts 生成新 ID并在响应头写入set-cookie保证购物车 ID 在首次请求即可用静态生成所有组合app/[code]/layout.tsxgenerateStaticParams调用generatePermutations(productFlags)一次性生成全部旗帜组合的code参数。文件注释同时给出了另一选项返回空数组以启用 ISR让各组合在首次渲染后被缓存——示例默认选择预先全量生成使所有变体在构建期就绪按编码反序列化布局层调用deserialize(productFlags, code)恢复该组合下每个旗帜的具体取值并渲染FlagValues values{values} /供客户端消费页面层则直接以await showSummerBannerFlag(code, productFlags)读取具体旗帜值见 app/[code]/page.tsx。flag()的第二个参数传入旗帜列表用于从编码中解析出本旗帜的取值。旗帜在业务代码中的实际消费示例中四个旗帜分别在业务组件中落地可直接作为集成范本横幅显示showSummerBannerFlag决定 components/banners/summer-sale-banner.tsx 是否渲染showFreeDeliveryBannerFlag在布局层决定 components/banners/free-delivery-banner.tsx 是否渲染结算按钮颜色proceedToCheckoutColorFlag返回blue | red | green在 components/shopping-cart/proceed-to-checkout-button.tsx 中通过colorMap映射为 Tailwind 类名bg-blue-600 hover:bg-blue-700等实现多态旗帜的样式切换接口延迟模拟delayFlag返回毫秒数在 lib/actions.ts 的getCart()服务端 Action 中通过await delay(delayMs)模拟后端延迟用于验证加载态与骨架屏colorMap中的skeleton分支对应animate-pulse占位样式。该文件还展示了旗帜在 Server Action 中的安全使用方式delayFlag()在服务端被调用客户端永不接触旗帜决策逻辑。常见注意事项旗帜命名必须一致Hypertune 控制台中的旗帜名delay、proceedToCheckout、freeDelivery、summerSale必须与 flags.ts 中的声明完全一致否则生成代码与消费端会对不上FLAGS_SECRET的格式必须是 32 字节随机数的 base64 编码直接复制其他值会导致 Flags Explorer 覆盖校验失败vercel linkvercel env pull是本地联调前置条件缺少本地环境变量时Flags Explorer 无法获得决策所需元数据模板适配器仅用于理解原理生产环境应使用flags-sdk/hypertune的真实适配器模板适配器template-adapter.ts帮助理解decide契约与确定性分桶算法后即可替换首屏 Cookie 时序首次访问时cart-id尚不存在需依赖代理层写入的x-generated-cart-id请求头与set-cookie响应头完成闭环详见 proxy.ts。至此你已经掌握了从 Hypertune Schema/L【免费下载链接】examplesEnjoy our curated collection of examples and solutions. Use these patterns to build your own robust and scalable applications.项目地址: https://gitcode.com/GitHub_Trending/examples1/examples创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表