跳转至

Mini Feature Flags —— Compile-Time DCE

演示 CC 真实代码用 esbuild define 实现的 95+ feature flag 编译时死代码消除。 3 flavors 对比:default / enterprise / oss。

文件

mini-feature-flags/
├── src/
│   ├── feature.ts  FLAVORS + applyFlavor + DCE(~50 行)
│   ├── source.ts   示例源代码(内联字符串)
│   └── cli.ts      演示 3 flavors
└── README.md

npm install && npm start

真实代码对照

Demo 真实文件 简化
applyFlavor esbuild define 插件 字符串替换
deadCodeElimination esbuild tree-shaking + minify 简单 if(false){} 匹配
feature() 函数 src/utils/feature.ts:30 抛"应被替换"错误

核心 4 件套

1️⃣ feature() 函数 = 占位符

function feature(name: "FOO"): boolean {
  throw new Error(`feature('${name}') should be replaced at build time`);
}
编译时被 esbuild define 替换为 true / false运行时函数体被消除,0 开销。

2️⃣ 3 Flavors = 3 商业产品

const FLAVORS = {
  default:    { SWARM_MODE: false, PRO_PLAN: false, AI_HELPER: true },
  enterprise: { SWARM_MODE: true,  PRO_PLAN: true,  AI_HELPER: true },
  oss:        { SWARM_MODE: false, PRO_PLAN: false, AI_HELPER: false },
};
CC 真实有 95+ feature flag + 3+ flavor。OSS 版 = enterprise feature 全关。

3️⃣ applyFlavor = 字符串替换

result = result.replace(/feature\(['"]SWARM_MODE['"]\)/g, "false");
esbuild define 等价:把 feature('SWARM_MODE') 全替换为 false / true 字面量。

4️⃣ DCE = 删 if(false) 块

source = source.replace(/if\s*\(\s*false\s*\)\s*\{[\s\S]*?\}\s*/g, "");
真实 esbuild tree-shaking更复杂(要分析控制流),但效果一样:if(false) 整段消失

3 Flavors 输出

📊 源代码: 665 bytes

🎯 Flavor: default
   替换后: 619 bytes
   DCE 后: 246 bytes (减少 63.0%)
   死代码清除: ✅
   剩余 if-constant: 1 个 (SWARM_MODE off, PRO_PLAN off, AI_HELPER on)

🎯 Flavor: enterprise
   替换后: 617 bytes
   DCE 后: 443 bytes (减少 33.4%)  ← 保留了所有 3 个 if(true){...}
   死代码清除: ✅
   剩余 if-constant: 3 个

🎯 Flavor: oss
   替换后: 620 bytes
   DCE 后: 154 bytes (减少 76.8%)  ← 最小,关闭所有
   死代码清除: ✅
   剩余 if-constant: 0 个

关键 insight: - oss 最瘦(77% 减少)—— 给开源社区用,零企业功能 - enterprise 最胖(33% 减少)—— 商业版给大客户 - default 居中(63% 减少)—— 给普通用户,少量 enterprise

真实 CC 数据(来自 deep-dive)

  • DCE 总量:v1.0 商业版 vs 内部 full 版 bundle 差 ~15%(约 200KB 消除)
  • 最大 feature:swarm mode 单独砍掉 30K 行代码
  • 构建时间:3 flavor 都要打,CI 5 分钟
  • 运行时检查feature() 在 production 永远不会被调用(DCE 已消除)

进阶练习

  1. 接真实 esbuild:用 esbuild API 做 build,看实际 bundle 差异
  2. 加 sourcemap mapping:记录 DCE 前后的行号对应
  3. 加 build report:列出每个 feature 砍掉多少行
  4. 加运行时 fallback:DCE 失败时 fallback 到环境变量
  5. 加 canary rollout:1% 流量开 feature,逐步放量
  6. 加 A/B testing:随机 50% 用户开 feature

相关阅读