AI 辅助的设计系统健康报告:自动生成组件使用率与弃用分析
一、"这个组件三年前写的,现在还有人在用吗?"
设计系统维护者常见困境:组件数量持续增长(300+),但没人知道哪些组件还在用、哪些已经"死"了、哪些被"滥用"了。删除一个组件需要手动调研三周,最后发现"不敢删,万一有人用呢"。
健康报告就是解决"组件库的未知债务"问题:自动扫描全量业务代码,统计每个组件的使用频率、使用方式(Props 组合)、最近使用时间,生成一份量化的组件健康度报告。
二、健康度评分模型
健康度评分模型通过全量代码扫描启动,自动提取组件引用并构建组件使用矩阵。基于该矩阵,系统从五个关键维度量化组件状态:使用频率(0-100 分)、Props 使用广度(0-100 分)、最近使用时间(30 天内满分,半年以上为 0 分)、使用趋势(增长/稳定/下降)以及兼容性问题(违反设计规范次数)。
上述维度数据将汇聚为综合健康分,并依据分数区间进行状态判定:
- 健康(> 80 分):广泛使用,状态良好。
- 注意(50-80 分):使用率下降,需关注。
- 危险(< 50 分):考虑弃用或重构。
- 死亡(0 分):可安全删除。
三、健康报告生成器
// health-report/component-health-analyzer.ts
// 组件健康度分析器
interface ComponentHealth {
componentName: string;
/** 总使用次数 */
usageCount: number;
—
/** 使用该组件的页面/模块数量 / usageScope: number; /* 最后使用日期 / lastUsedDate: string; /* Props 使用率:被使用的 Props / 总 Props / propsUsageRate: number; /* 僵尸 Props:定义了但从未被使用的 Props / zombieProps: string[]; /* 使用趋势:最近 3 个月 vs 前 3 个月 / trend: 'growing' | 'stable' | 'declining' | 'new' | 'dead'; /* 设计规范违规次数(不推荐用法) / designViolations: number; /* 综合健康分 0-100 / healthScore: number; /* 建议操作 */ recommendation: 'keep' | 'monitor' | 'refactor' | 'deprecate' | 'remove';}
/**
-
设计系统健康报告生成器
-
扫描整个 monorepo,分析每个组件的使用情况 /class HealthReportGenerator { /*
- 生成全量健康报告*/async generateReport(projectRoots: string[]): Promise<ComponentHealth[]> { const allUsages = await this.scanAllProjects(projectRoots); const componentDefs = await this.loadComponentDefinitions();
const healths: ComponentHealth[] = [];
for (const [name, def] of Object.entries(componentDefs)) { const usage = allUsages.filter(u => u.componentName === name);
// 计算 Props 使用率 const usedProps = new Set(); usage.forEach(u => { Object.keys(u.props).forEach(p => usedProps.add(p)); });
const totalDefinedProps = def.props.length; const propsUsageRate = totalDefinedProps > 0 ? usedProps.size / totalDefinedProps : 1;
// 僵尸 Props const zombieProps = def.props .filter(p => !usedProps.has(p.name)) .map(p => p.name);
// 使用趋势 const trend = this.calcTrend(usage, name);
// 健康分计算 const healthScore = this.calcHealthScore({ usageCount: usage.length, usageScope: new Set(usage.map(u => u.file)).size, propsUsageRate, zombiePropCount: zombieProps.length, trend, violations: 0 });
// 建议 const recommendation = this.getRecommendation( healthScore, usage.length, trend );
healths.push({ componentName: name, usageCount: usage.length, usageScope: new Set(usage.map(u => u.file)).size, lastUsedDate: this.getLastUsedDate(usage), propsUsageRate: Math.round(propsUsageRate * 100) / 100, zombieProps, trend, designViolations: 0, healthScore, recommendation }); }
return healths.sort((a, b) => b.usageCount – a.usageCount); }
/**
- 健康分计算
- 权重分配:
-
- 使用频率: 30%
-
- 使用广度: 20%
-
- Props 使用率: 20%
-
- 近期活跃度: 15%
-
- 趋势: 10%
-
- 违规扣分: 5% */private calcHealthScore(params: { usageCount: number; usageScope: number; propsUsageRate: number; zombiePropCount: number; trend: string; violations: number;}): number { let score = 0;
// 使用频率(0-30分)
if (params.usageCount === 0) {
score += 0;
} else if (params.usageCount < 5) {
score += 10;
} else if (params.usageCount < 20) {
score += 20;
} else {
score += 30;
}
// 使用广度(0-20分)
if (params.usageScope >= 20) score += 20;
else if (params.usageScope >= 10) score += 15;
else if (params.usageScope >= 3) score += 10;
else if (params.usageScope > 0) score += 5;
// Props 使用率(0-20分)
score += Math.round(params.propsUsageRate * 20);
// 近期活跃度(0-15分)
// 由 calcTrend 内部赋值
// 趋势分数(0-10分)
switch (params.trend) {
case 'growing': score += 10; break;
case 'stable': score += 7; break;
case 'new': score += 5; break;
case 'declining': score += 2; break;
case 'dead': score += 0; break;
}
// 违规扣分(-5分上限)
score -= Math.min(5, params.violations);
// 僵尸 Props 扣分
score -= Math.min(5, params.zombiePropCount * 2);
return Math.max(0, Math.min(100, score));
}
/**
- 使用趋势计算 */ private calcTrend(usages: any[],componentName: string ): 'growing' | 'stable' | 'declining' | 'new' | 'dead' {if (usages.length === 0) return 'dead';
const threeMonthsAgo = Date.now() – 90 * 24 * 60 * 60 * 1000;
const sixMonthsAgo = Date.now() – 180 * 24 * 60 * 60 * 1000;
const recent = usages.filter(u => u.date > threeMonthsAgo).length;
const older = usages.filter(
u => u.date > sixMonthsAgo && u.date <= threeMonthsAgo
).length;
if (older === 0 && recent > 0) return 'new';
if (recent > older * 1.2) return 'growing';
if (recent < older * 0.8) return 'declining';
return 'stable';
}
private getRecommendation( score: number, usageCount: number, trend: string ): ComponentHealth['recommendation'] { if (usageCount === 0) return 'remove'; if (score < 30) return 'deprecate'; if (score < 50) return 'refactor'; if (score < 70) return 'monitor'; return 'keep'; }
private getLastUsedDate(usages: any[]): string { if (usages.length === 0) return '从未使用'; const latest = Math.max(…usages.map(u => u.date)); return new Date(latest).toISOString().split('T')[0]; }
private async scanAllProjects(roots: string[]): Promise<any[]> { // 扫描所有项目的代码文件,提取组件使用记录 return []; }
private async loadComponentDefinitions(): Promise<Record<string, any>> { // 加载组件库的组件定义文件 return {}; }}
/**
- 生成 Markdown 格式的健康报告 */function generateMarkdownReport(healths: ComponentHealth[]): string { const total = healths.length; const healthy = healths.filter(h => h.recommendation === 'keep').length; const atRisk = healths.filter(h => ['monitor', 'refactor'].includes(h.recommendation)).length; const deprecated = healths.filter(h => ['deprecate', 'remove'].includes(h.recommendation)).length;
let report = # 设计系统健康报告\\n\\n; report += – 总组件数: ${total}\\n; report += – 健康: ${healthy} | 关注: ${atRisk} | 危险: ${deprecated}\\n\\n;
report += ## 危险组件(建议弃用或删除)\\n\\n; report += | 组件 | 使用次数 | 健康分 | 建议 |\\n; report += |——|———|——–|——|\\n;
for (const h of healths.filter(h => h.recommendation === 'deprecate' || h.recommendation === 'remove')) { report += | ${h.componentName} | ${h.usageCount} | ${h.healthScore} | ${h.recommendation} |\\n; }
report += \\n## 僵尸 Props(定义了但从未使用的 Props)\\n\\n; for (const h of healths.filter(h => h.zombieProps.length > 0)) { report += ### ${h.componentName}\\n; for (const prop of h.zombieProps) { report += – \\${prop}`\\n`; } report += '\\n'; }
return report;}
## 四、健康报告的时效性与可信度
**代码扫描的覆盖率**。如果只扫描 `src/` 目录,遗漏了测试文件、Storybook Stories 等间接使用场景,报告的"使用次数"会低估。建议扫描范围包括:`.tsx`、`.jsx`、`.ts` 文件中所有 JSX 标签和 `createElement` 调用。
**使用频率不反映重要性**。一个"只在首页用了一次"的关键 CTA 按钮组件比一个"在 50 个后台页面使用"的普通表单字段更重要。健康分需要加入"使用位置的权重"——首页使用权重高于设置页。
**Git 历史提供趋势数据**。仅扫描当前代码只能得到"现状",结合 Git 历史可以分析"过去半年的使用趋势"——这是健康报告中"trend"字段的价值来源。
## 五、总结
设计系统健康报告将组件库的维护从"凭感觉"变成"看数据":
1. **使用矩阵**——每个组件被多少个页面/模块使用
2. **Props 分析**——哪些 Props 是僵尸属性(定义但从未使用)
3. **趋势判断**——使用量在增长还是下降
4. **操作建议**——删除 / 弃用 / 重构 / 监控 / 保持
这份报告应该**每周自动生成**,发布到团队 Slack 频道或维护者 Dashboard 中。不是为了让谁去读,而是当某个组件的健康分持续下降时,自动触发"是否需要重构"的讨论。

