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;
- 违规扣分: 5%
// 使用频率(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 中。不是为了让谁去读,而是当某个组件的健康分持续下降时,自动触发"是否需要重构"的讨论。