使用 Vercel Flags SDK 与 Flags Explorer 构建 Next.js 功能开关:flags-sdk/vercel 示例深度解析
【免费下载链接】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/vercel 示例展开,系统讲解如何通过@flags-sdk/vercel适配器将 Flags SDK 与 Vercel 原生 Feature Flags 能力打通,在 Next.js 电商页面中用功能开关控制横幅显隐与结算按钮颜色,并借助 Flags Explorer 在本地实时切换开关。读完本文,你将掌握从 Vercel Dashboard 创建开关、到flags.ts声明、再到proxy.ts预计算与路由重写的完整落地链路,可直接复用到自己的项目中。
示例整体架构:从 Flag 定义到页面渲染的完整链路
本示例是一个典型的 Next.js 电商商品详情页 + 购物车 Demo,核心演示了三类典型用法:
- 布尔开关:控制页面顶部促销横幅(summer sale、free delivery)的显示与隐藏;
- 字符串开关:控制"Proceed to Checkout"(去结算)按钮的颜色(
blue/green/red); - 本地调试能力:通过 Flags Explorer 在本地开发环境实时覆盖开关取值,无需改动代码。
Flag 配置全部托管在 Vercel Dashboard(项目控制台的Flags标签页),应用侧只负责"声明"与"消费"。整个数据流分为四层,可从仓库源码逐一印证:
- flags.ts:集中声明所有 Flag 的定义(key、默认值、可选值、描述);
- proxy.ts:Next.js 中间件(proxy),对请求做 Flag 预计算(
precompute),并把请求重写到携带组合编码的动态路由/[code]; - 路由页面:app/[code]/page.tsx 等页面按
code读取 Flag 值并渲染对应 UI; - Vercel 平台:Dashboard 中的 Flag 配置与
FLAGS/FLAGS_SECRET环境变量负责提供取值来源。
需要说明的是:
proxy.ts是 Next.js 16 中由middleware.ts演进而来的新命名约定,仓库中该文件通过export const config = { matcher: [...] }指定拦截范围,功能等价于传统中间件。
第一步:在 flags.ts 中声明功能开关
所有 Flag 都集中定义在 flags.ts,使用 Flags SDK 的flag()工厂函数创建,并通过createVercelAdapter()将取值交给 Vercel Flags 后端:
import { flag } from 'flags/next' import { createVercelAdapter } from '@flags-sdk/vercel' import { identify, type Entities } from './lib/identify' const vercelFlagsAdapter = createVercelAdapter() export const showSummerBannerFlag = flag<boolean, Entities>({ key: 'summer-sale', adapter: vercelFlagsAdapter(), defaultValue: false, identify, description: 'Show the summer sale banner', options: [ { value: true, label: 'Show' }, { value: false, label: 'Hide' }, ], }) export const showFreeDeliveryBannerFlag = flag<boolean, Entities>({ key: 'free-delivery', adapter: vercelFlagsAdapter(), defaultValue: false, identify, description: 'Show the free delivery banner', options: [ { value: true, label: 'Show' }, { value: false, label: 'Hide' }, ], }) export const proceedToCheckoutColorFlag = flag<string, Entities>({ key: 'proceed-to-checkout-color', adapter: vercelFlagsAdapter(), defaultValue: 'blue', identify, description: 'Color of the proceed to checkout button', options: [ { value: 'blue', label: 'Blue' }, { value: 'green', label: 'Green' }, { value: 'red', label: 'Red' }, ], }) export const productFlags = [ showFreeDeliveryBannerFlag, showSummerBannerFlag, proceedToCheckoutColorFlag, ] as const关键字段说明
| 字段 | 含义 | 本示例取值 |
|---|---|---|
key | Flag 的唯一标识,必须与 Vercel Dashboard 中创建的 Flag key 完全一致 | summer-sale、free-delivery、proceed-to-checkout-color |
adapter | 取值适配器,vercelFlagsAdapter()负责与 Vercel Flags 后端通信 | 三个 Flag 均使用 |
defaultValue | 未配置或取不到值时使用的兜底默认值 | false/false/'blue' |
identify | 标识当前访问者(实体),用于按用户维度解析 Flag | 统一使用lib/identify.ts的 stable id |
options | 可选项列表,会同步展示在 Flags Explorer 与 Vercel Dashboard 中,便于可视化切换 | 见上表 |
description | 人类可读描述,帮助团队理解该开关用途 | 各 Flag 均有 |
泛型与实体识别(identify)
flag<boolean, Entities>中的第二个泛型参数Entities来自 lib/identify.ts,声明了访问者实体的结构:
export type Entities = { user?: { id: string } }identify函数通过dedupe包裹(同一请求内只执行一次),从stable-idCookie 中读取用户标识并作为user.id上报:
export const identify = dedupe(async (): Promise<Entities> => { const stableId = await getStableId() return { user: { id: stableId.value }, } }) satisfies Identify<Entities>stable-id的生成逻辑在 lib/get-stable-id.ts:优先读取请求头x-generated-stable-id(首次请求由 proxy 生成并注入),其次读stable-idCookie,都没有则用nanoid()现场生成并标记为"新生成"。购物车场景下还有一个并行的cart-id(见 lib/get-cart-id.ts),两者逻辑一致,共同支撑"无登录用户也能按稳定身份解析 Flag"的能力。
第二步:在 Vercel Dashboard 创建功能开关
Flag 配置不需要写代码,直接在 Vercel 项目控制台的Flags标签页创建即可。README 要求创建以下三个开关:
| Flag Key | 类型 | 可选值 / 默认值 | 用途 |
|---|---|---|---|
summer-sale | Boolean | true/false(默认false) | 控制夏季促销横幅显隐 |
free-delivery | Boolean | true/false(默认false) | 控制免运费横幅显隐 |
proceed-to-checkout-color | String | blue、green、red(默认blue) | 控制结算按钮颜色 |
所有 Flag 的 key 都声明在 flags.ts 中,创建时务必与之一一对应。仓库还内置了一个 setup 页面,它会以清单(checklist)形式列出全部必需 Flag 的 key、类型、默认值与一键创建链接,并实时显示FLAGS_SECRET环境变量是否已配置(Configured / Missing 状态徽标),方便部署后自查。
第三步:部署与本地开发全流程
一键部署
README 提供了 Vercel 部署入口,点击后会依次完成三件事:
- 将该仓库克隆到你的 GitHub 账户;
- 创建一个新的 Vercel 项目;
- 立即触发部署——即使你还没有配置任何 Flag,应用也能先跑起来(未配置时会自动进入 setup 引导页,详见下文)。
Step 1:链接本地项目
要使用 Flags Explorer,需要先把本地项目与云端项目关联:
vercel link按提示从列表中选中刚部署的项目即可。
Step 2:在 Vercel Dashboard 创建功能开关
打开项目控制台的Flags标签页,按上文表格创建summer-sale、free-delivery、proceed-to-checkout-color三个开关。
Step 3:拉取环境变量
执行以下命令拉取包含 SDK 密钥的FLAGS环境变量:
vercel env pullStep 4:安装依赖并启动开发服务器
pnpm install pnpm dev依赖清单见 package.json,核心依赖包括@flags-sdk/vercel@1.4.5、@vercel/flags-core@1.7.0、flags@4.1.0以及 Next.js 16 与 React 19。
本地开发要点
本地调试时需确保满足三点:
- 已用
vercel link关联项目; - 已用
vercel env pull拉取环境变量; - 在
.env.local中设置FLAGS_SECRET——它用于 Flags 预计算(precompute),并保障 Flags Explorer 本地覆盖(override)的安全性。
第四步:未配置时的降级行为(/setup 引导页)
README 明确说明:如果FLAGS或FLAGS_SECRET缺失,请求会被重写到/setup,直到配置完成。这一逻辑在 proxy.ts 中实现:
export async function proxy(request: NextRequest) { const hasFlagsSecret = Boolean(process.env.FLAGS_SECRET) if (!hasFlagsSecret) { return NextResponse.rewrite(new URL('/setup', request.url)) } // ... }setup 页面 承担"配置向导"职责:展示必需 Flag 清单表格(Key / Type / Default / Description)并提供"Create"跳转链接,同时提示执行vercel env pull获取FLAGS。这一设计让模板"开箱即用、逐步配置",即使先部署后配置也不会白屏报错。
源码深潜:proxy 预计算与按组合编码重写
proxy.ts是本示例的技术核心,它把"Flag 组合"编码进 URL,从而让服务端渲染天然感知开关状态:
import { type NextRequest, NextResponse } from 'next/server' import { precompute } from 'flags/next' import { getStableId } from './lib/get-stable-id' import { getCartId } from './lib/get-cart-id' export const config = { matcher: ['/', '/cart'], } export async function proxy(request: NextRequest) { const hasFlagsSecret = Boolean(process.env.FLAGS_SECRET) if (!hasFlagsSecret) { return NextResponse.rewrite(new URL('/setup', request.url)) } // Demo-only: lazily import flags after env validation to avoid loading // the provider setup before users complete /setup. const { productFlags } = await import('@/flags') const stableId = await getStableId() const cartId = await getCartId() const code = await precompute(productFlags) // rewrites the request to the variant for this flag combination const nextUrl = new URL( `/${code}${request.nextUrl.pathname}${request.nextUrl.search}`, request.url ) if (cartId.isFresh) { request.headers.set('x-generated-cart-id', cartId.value) } if (stableId.isFresh) { request.headers.set('x-generated-stable-id', stableId.value) } const headers = new Headers() headers.append('set-cookie', `stable-id=${stableId.value}`) headers.append('set-cookie', `cart-id=${cartId.value}`) return NextResponse.rewrite(nextUrl, { request, headers }) }关键点拆解:
- 拦截范围:
matcher: ['/', '/cart'],只对首页与购物车页做预计算,其他路由直通; - 环境校验前置:
FLAGS_SECRET缺失时直接重写到/setup,避免在用户未完成配置前加载 Provider(源码注释明确说明这是 Demo 专用策略); - 编码化路由:
precompute(productFlags)把三个 Flag 的当前取值编码为一段 code,请求被重写到/{code}{原路径}。例如首页/可能被重写为/<code>/; - 首访身份注入:首次请求没有 Cookie,proxy 生成的
stable-id/cart-id通过x-generated-stable-id/x-generated-cart-id请求头注入,同时在响应中写回同名 Cookie,保证后续请求与identify逻辑能读到一致身份; - 预计算的意义:把 Flag 取值"固化"在请求发生前,服务端渲染时无需再发起网络请求,天然适配缓存,这也是为什么要在
next.config.mjs中开启cacheComponents: true。
路由侧如何消费 Flag
以首页为例(app/[code]/page.tsx),页面组件通过params.code与 flag 定义一起解析取值:
const params = await props.params const showSummerBanner = await showSummerBannerFlag(params.code, productFlags)showSummerBannerFlag(params.code, productFlags)的调用方式表明:传入编码与全部 Flag 列表,SDK 即可从编码中还原出当前 Flag 的值,无需在渲染阶段访问外部服务。得到布尔值后,组件 app/summer-sale.tsx 与 app/free-delivery.tsx 决定是否渲染对应横幅(show ? <Banner/> : null)。结算按钮颜色同理,由 proceed-to-checkout.tsx 接收color字符串并传给按钮组件。
配合 Flags Explorer 做本地可视化调试
Flags Explorer 是 Vercel Flags 的本地调试工具,其入口来自 next.config.mjs 中的 Vercel Toolbar 插件:
import withVercelToolbar from '@vercel/toolbar/plugins/next' const nextConfig = { cacheComponents: true, turbopack: { root: path.join(__dirname, ".."), }, } export default withVercelToolbar()(nextConfig)withVercelToolbar()为开发环境注入 Toolbar,使得运行pnpm dev后,页面上会出现调试入口,你可以在 Flags Explorer 面板中即时启用/禁用summer-sale、free-delivery或切换proceed-to-checkout-color的颜色值,改动即时生效,无需改动代码或重新部署。为了让它正常工作,必须满足前面提到的三个前提:项目已vercel link、已vercel env pull、且.env.local中设置了FLAGS_SECRET(预计算与安全的本地覆盖都依赖它)。
小结:完整落地清单
要在你自己的项目中复刻这套方案,按以下顺序操作即可:
- 部署:通过 Vercel 一键部署模板(或
git clone本仓库后自行部署),无需预先配置 Flag; - 建 Flag:在项目控制台 Flags 标签页创建
summer-sale(Boolean)、free-delivery(Boolean)、proceed-to-checkout-color(String,blue/green/red); - 本地联调:
vercel link→vercel env pull→ 在.env.local写入FLAGS_SECRET→pnpm install && pnpm dev; - 可视化调试:打开 Flags Explorer,实时切换三个开关观察横幅与按钮颜色的变化;
- 上线发布:在 Vercel Dashboard 中把开关调到目标取值并部署发布。
本示例的完整源码与配置均可在本仓库 flags-sdk/vercel 目录下查看,其中 flags.ts 是 Flag 声明的唯一事实来源,proxy.ts 是预计算与重写的中枢,setup 页面 则保证了"先部署、后配置"的平滑体验。建议在此基础上扩展你自己的 Flag key 与业务组件,即可快速搭建一套生产可用的 Vercel Flags 功能开关体系。
【免费下载链接】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),仅供参考