特性门控系统
编译时特性门控不是什么新概念,C/C++ 的条件编译用了几十年了。但在 TypeScript 项目里做到这个程度的,Claude Code 算是头一个让我觉得做得漂亮的。
核心机制
一个 feature() 函数,编译时求值:
typescript
if (feature('BRIDGE_MODE')) {
// 这段代码只在 Bridge 构建产物中存在
// 其他构建产物里,整个 if 块被删掉
await import('./bridge/handler')
}不是运行时判断,是编译时死代码消除。构建产物里根本不包含未启用功能的代码。
为什么需要这个
Claude Code 有多个部署目标:
- 公开版:普通用户下载的 npm 包
- 内部版:Anthropic 内部构建,功能更多
- 企业版:特定企业功能
同一套代码,通过 feature gate 编译出不同的产物。不需要维护多个分支,也不用在运行时浪费资源判断一堆用不到的功能。
特性标志分类
核心功能
| 标志 | 用途 |
|---|---|
BRIDGE_MODE | Web 端通信(claude.ai 桥接) |
DAEMON | 守护进程模式 |
VOICE_MODE | 语音输入 |
TEMPLATES | 项目模板系统 |
BG_SESSIONS | 后台会话管理 |
工具与功能
大约 47 个编译时标志,控制各种工具和功能的启用:
AGENT_TRIGGERS— Agent 触发器WEB_BROWSER_TOOL— 网页浏览工具WORKFLOW_SCRIPTS— 工作流编排TOKEN_BUDGET— Token 预算管理COMPUTER_USE— 计算机操作CHICAGO_MCP— Computer Use MCP 服务器
企业级
COORDINATOR_MODE— 多 Agent 协调器ULTRAPLAN— 高级规划功能BYOC_ENVIRONMENT_RUNNER— 自带环境运行器SELF_HOSTED_RUNNER— 自托管运行器
运行时门控
除了编译时的 feature(),还有 GrowthBook 做运行时门控:
typescript
// 运行时判断,不影响构建产物
if (growthbook.isOn('new_model_default')) {
setModel('claude-sonnet-4-6')
}两层门控各有用途:
| 编译时 | 运行时 | |
|---|---|---|
| 机制 | feature() | GrowthBook |
| 生效方式 | 构建时删代码 | 远程配置刷新 |
| 适用场景 | 不同部署目标 | A/B 测试、灰度 |
| 更新成本 | 需要重新构建 | 即时生效 |
在代码中的体现
feature gate 遍布关键路径:
- cli.tsx:约 30 个 feature-gated 路由路径
- tools.ts:控制工具注册——某些工具只在特定构建中存在
- keybindings:部分快捷键绑定依赖特定标志
这意味着公开版和内部版的 Claude Code,代码路径可能差异很大,但维护的是同一套源码。
注意
源站原文档列出的一些标志(如 REPL_TOOL、SLEEP_TOOL 等)在实际代码中并不存在。本文已做修正,以实际源码为准。