mcpField
F
feature-flags

feature-flags

github.com/tushaarmehtaa开发1240 次安装2 周前更新
代码仓库

关于 feature-flags

用于在应用中端到端接入 PostHog 功能标志的开发技能,涵盖服务端评估、客户端钩子和本地覆盖。它会先检查项目现有配置,并在已有 PostHog 集成上扩展。

主要功能

  1. 01检查现有 PostHog 配置
  2. 02在服务端评估标志
  3. 03交互后使用客户端钩子
  4. 04在本地开发中覆盖标志
  5. 05指导在 PostHog 中创建标志

适用场景

  1. 01控制路由或页面内容且避免初始闪烁
  2. 02按用户标志控制 API 行为
  3. 03在本地测试标志变体

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/tushaarmehtaa/tushar-skills --skill feature-flags

安装后在 Claude Code 中输入/feature-flags确认已加载。

详细介绍

端到端接入 PostHog 功能标记——服务端评估、客户端 Hook 和本地开发覆盖。先读取项目,再扩展现有的 PostHog 配置(如果有)。

两个会悄悄导致 PostHog 功能标记失效的问题

  1. 需要服务端行为时,却在客户端评估功能标记。 useFeatureFlagEnabled 会在水合后于浏览器中运行。如果你用功能标记控制页面某个区域的显示或隐藏,该区域会先闪现,然后消失。对于首屏可见内容或会影响路由的内容,应在服务端评估功能标记。
  2. 服务端调用缺少 distinctId。 PostHog 的服务端 SDK 需要唯一的用户标识符来评估功能标记。使用 "anonymous" 这类占位符意味着所有未认证用户都会获得相同的功能标记变体——这不是逐步放量,而是固定值。

第 1 阶段:检测项目

cat package.json | grep -E "posthog"
grep -r "posthog" src/ app/ --include="*.ts" --include="*.tsx" -l 2>/dev/null | head -5
  • 已安装 posthog-js 且找到 Provider? → 已配置 PostHog 客户端。在此基础上添加服务端 SDK。
  • 已安装 posthog-node? → 扩展现有配置,不要重新安装。
  • 都没有? → 先使用 add-analytics 技能从头接入 PostHog,然后回到这里。

第 2 阶段:安装服务端 SDK

npm install posthog-node

添加到 .env.example(如果已运行 add-analytics 技能,则已设置):

NEXT_PUBLIC_POSTHOG_KEY=
POSTHOG_API_KEY=   # same as POSTHOG_KEY — use for server-side calls

第 3 阶段:服务端功能标记客户端

创建用于服务端评估的单例:

// lib/posthog-server.ts
import { PostHog } from 'posthog-node';

let client: PostHog | null = null;

export function getPostHogServer(): PostHog {
  if (!client) {
    client = new PostHog(process.env.POSTHOG_API_KEY!, {
      host: 'https://us.i.posthog.com',
      flushAt: 1,      // flush immediately in serverless
      flushInterval: 0,
    });
  }
  return client;
}

export async function isFeatureEnabled(
  flagKey: string,
  distinctId: string,
  groups?: Record<string, string>
): Promise<boolean> {
  const ph = getPostHogServer();
  const result = await ph.isFeatureEnabled(flagKey, distinctId, { groups });
  return result ?? false;
}

export async function getFeatureFlagVariant(
  flagKey: string,
  distinctId: string
): Promise<string | boolean | undefined> {
  const ph = getPostHogServer();
  return ph.getFeatureFlag(flagKey, distinctId);
}

第 4 阶段:服务端组件用法

在服务端组件和路由处理程序中评估功能标记——不会出现客户端闪烁:

// app/dashboard/page.tsx (Server Component)
import { isFeatureEnabled } from '@/lib/posthog-server';
import { getAuthUser } from '@/lib/auth';

export default async function DashboardPage() {
  const user = await getAuthUser();

  const showNewDashboard = user
    ? await isFeatureEnabled('new-dashboard', user.id)
    : false;

  return showNewDashboard ? <NewDashboard /> : <OldDashboard />;
}
// app/api/generate/route.ts (Route Handler)
import { isFeatureEnabled } from '@/lib/posthog-server';

export async function POST(req: Request) {
  const user = await getAuthUser(req);
  if (!user) return Response.json({ error: 'Unauthorized' }, { status: 401 });

  const hasStreamingAccess = await isFeatureEnabled('streaming-responses', user.id);

  if (hasStreamingAccess) {
    return handleStreaming(req, user);
  }
  return handleNonStreaming(req, user);
}

第 5 阶段:客户端用法

对于用户交互后才会改变 UI 的功能标记(而非初始渲染时):

// components/feature-flagged-button.tsx
'use client';
import { useFeatureFlagEnabled } from 'posthog-js/react';

export function NewFeatureButton() {
  const isEnabled = useFeatureFlagEnabled('new-export-feature');

  // useFeatureFlagEnabled returns undefined while loading
  if (isEnabled === undefined) return null;
  if (!isEnabled) return null;

  return <button>Export (New)</button>;
}

切勿对首屏可见内容使用客户端 Hook。 Hook 在首次渲染时会返回 undefined,导致布局偏移。对于页面加载时可见的任何内容,都应使用服务端方案。

第 6 阶段:本地开发覆盖

添加仅用于开发环境的功能标记覆盖机制,以便在本地测试两个变体,而无需操作 PostHog:

// lib/posthog-server.ts (add to existing file)
export async function isFeatureEnabled(
  flagKey: string,
  distinctId: string,
  groups?: Record<string, string>
): Promise<boolean> {
  // Local override for development
  if (process.env.NODE_ENV === 'development') {
    const override = process.env[`FLAG_${flagKey.toUpperCase().replace(/-/g, '_')}`];
    if (override === 'true') return true;
    if (override === 'false') return false;
  }

  const ph = getPostHogServer();
  const result = await ph.isFeatureEnabled(flagKey, distinctId, { groups });
  return result ?? false;
}

在 .env.local 中:

FLAG_NEW_DASHBOARD=true    # force-enable new-dashboard flag locally
FLAG_STREAMING_RESPONSES=false  # force-disable

第 7 阶段:在 PostHog 中创建功能标记

明确告知用户需要设置的内容。在 PostHog 控制面板中:

  1. 功能标记 → 新建功能标记
  2. 键:new-dashboard(与代码中的值一致)
  3. 放量:从 0% 开始,逐步增加到 10%、50%、100%
  4. 条件:可按用户属性(plan = 'pro')、群组或百分比进行定向

对于 A/B 测试:使用“多个变体”而不是布尔值。然后使用 getFeatureFlagVariant() 并返回 'control' 或 'test'。

验证

[ ] posthog-node installed
[ ] POSTHOG_API_KEY in .env.example
[ ] Server-side evaluation uses real user ID as distinctId — not "anonymous"
[ ] Server Components use isFeatureEnabled() — not the client hook
[ ] Client hook used only for post-hydration interactions, not initial render
[ ] Local override via FLAG_* env vars works in development
[ ] Flags created in PostHog dashboard with matching key names
[ ] Test: set FLAG_[KEY]=false in .env.local — confirm feature is hidden
[ ] Test: set FLAG_[KEY]=true in .env.local — confirm feature is shown
[ ] PostHog flag set to 0% rollout first — expand after confirming it works

评论

支持 Markdown