在现代前端开发中,随着业务需求不断变化和技术栈持续演进,项目中不可避免地会积累大量冗余代码。
最近,我在做功能迭代的时候,发现有些代码已经不再使用,但是代码块还保留着。我再梳理功能时,产生了困惑,找到之前对应的业务负责人才了解了最新的业务。
可见,这些"代码债务"不仅增加了项目的维护成本,还会影响构建性能和新功能的开发效率。
本文将分享一套在React项目中安全、系统化清理代码的方法论,涵盖从静态分析验证到渐进式移除的全流程策略。我们特别关注如何在大型团队协作环境中,平衡清理效率与系统稳定性,避免因代码清理引入新的问题。
静态分析是代码清理的第一步,也是确保安全移除的基础。通过自动化工具和人工审查相结合的方式,我们可以准确识别出哪些代码是真正可以安全移除的。
推荐工具组合:
// package.json
{
"scripts": {
"analyze": "eslint --ext .js,.jsx,.ts,.tsx --report-unused-disable-directives src",
"type-check": "tsc --noEmit --listFiles",
"bundle-report": "webpack-bundle-analyzer stats.json"
},
"devDependencies": {
"eslint-plugin-unused-imports": "^2.0.0",
"ts-prune": "^1.3.0",
"webpack-bundle-analyzer": "^4.7.0"
}
}
架构解析:
no-unused-vars
规则和unused-imports
插件检测未使用的变量和导入ts-prune
可找出未被导出的类型定义// 依赖关系分析工具
class DependencyAnalyzer {
constructor() {
this.dependencies = new Map(); // 存储依赖关系
this.references = new Map(); // 存储引用关系
this.entryPoints = new Set(); // 存储入口点
}
/**
* 分析模块依赖关系
* @param {string} filePath - 文件路径
* @param {string} content - 文件内容
*/
analyzeFile(filePath, content) {
// 解析ES6导入语句
const importRegex = /import\s+(?:{([^}]+)}|(\w+)|\*\s+as\s+(\w+))\s+from\s+['"]([^'"]+)['"]/g;
let match;
while ((match = importRegex.exec(content)) !== null) {
const [, namedImports, defaultImport, namespaceImport, source] = match;
const imports = [];
if (namedImports) {
imports.push(...namedImports.split(',').map(i => i.trim()));
}
if (defaultImport) {
imports.push('default');
}
if (namespaceImport) {
imports.push('*');
}
this.addDependency(filePath, source, imports);
}
// 解析CommonJS require语句
const requireRegex = /require\(['"]([^'"]+)['"]\)/g;
while ((match = requireRegex.exec(content)) !== null) {
this.addDependency(filePath, match[1], ['*']);
}
}
/**
* 添加依赖关系
* @param {string} from - 源文件
* @param {string} to - 目标文件
* @param {Array} imports - 导入的符号
*/
addDependency(from, to, imports) {
if (!this.dependencies.has(from)) {
this.dependencies.set(from, new Map());
}
const fileDeps = this.dependencies.get(from);
if (!fileDeps.has(to)) {
fileDeps.set(to, new Set());
}
imports.forEach(importItem => fileDeps.get(to).add(importItem));
// 建立反向引用关系
if (!this.references.has(to)) {
this.references.set(to, new Set());
}
this.references.get(to).add(from);
}
/**
* 查找未使用的导出
* @param {string} filePath - 文件路径
* @returns {Array} 未使用的导出列表
*/
findUnusedExports(filePath) {
const content = this.getFileContent(filePath);
const exports = this.parseExports(content);
const usedExports = this.getUsedExports(filePath);
return exports.filter(exp => !usedExports.has(exp));
}
/**
* 解析文件中的导出语句
* @param {string} content - 文件内容
* @returns {Array} 导出的符号列表
*/
parseExports(content) {
const exports = [];
// 解析ES6命名导出
const namedExportRegex = /export\s+{([^}]+)}/g;
let match;
while ((match = namedExportRegex.exec(content)) !== null) {
const items = match[1].split(',').map(item => {
const parts = item.trim().split(/\s+as\s+/);
return parts[parts.length - 1]; // 返回导出名称
});
exports.push(...items);
}
// 解析默认导出
if (/export\s+default/.test(content)) {
exports.push('default');
}
// 解析变量导出
const varExportRegex = /export\s+(?:const|let|var|function|class)\s+(\w+)/g;
while ((match = varExportRegex.exec(content)) !== null) {
exports.push(match[1]);
}
return [...new Set(exports)]; // 去重
}
/**
* 获取被使用的导出
* @param {string} filePath - 文件路径
* @returns {Set} 被使用的导出集合
*/
getUsedExports(filePath) {
const usedExports = new Set();
const referencingFiles = this.references.get(filePath) || [];
referencingFiles.forEach(refFile => {
const deps = this.dependencies.get(refFile);
if (deps && deps.has(filePath)) {
deps.get(filePath).forEach(exportName => {
usedExports.add(exportName);
});
}
});
return usedExports;
}
}
使用示例:
const analyzer = new DependencyAnalyzer();
// 分析项目中的所有文件
projectFiles.forEach(file => {
analyzer.analyzeFile(file.path, file.content);
});
// 查找未使用的导出
const unusedExports = projectFiles
.map(file => ({
file: file.path,
unused: analyzer.findUnusedExports(file.path)
}))
.filter(result => result.unused.length > 0);
架构解析: 模块依赖关系分析器,用于分析代码文件之间的依赖关系并识别未使用的导出。
设计思路: 通过解析代码中的导入导出语句,建立完整的依赖图,从而识别哪些导出从未被使用过。
重点逻辑:
参数解析:
dependencies
: 存储文件依赖关系的Map。references
: 存储反向引用关系的Map。imports
: 导入的符号数组。为了确保代码移除的安全性,我们需要采用渐进式的清理流程,而不是一次性删除所有可疑代码。
// 代码标记系统
class CodeMarker {
constructor() {
this.markers = new Map(); // 存储代码标记
this.markerTypes = {
DEPRECATED: 'deprecated', // 已废弃
UNUSED: 'unused', // 未使用
REDUNDANT: 'redundant', // 冗余代码
EXPERIMENTAL: 'experimental' // 实验性代码
};
}
/**
* 标记代码片段
* @param {Object} options - 标记选项
* @param {string} options.filePath - 文件路径
* @param {number} options.lineStart - 起始行号
* @param {number} options.lineEnd - 结束行号
* @param {string} options.type - 标记类型
* @param {string} options.reason - 标记原因
* @param {string} options.replacement - 替代方案
*/
markCode(options) {
const {
filePath,
lineStart,
lineEnd,
type,
reason,
replacement,
markedBy,
markedAt
} = options;
const markerId = `${filePath}:${lineStart}-${lineEnd}`;
const marker = {
id: markerId,
filePath,
lineStart,
lineEnd,
type,
reason,
replacement,
markedBy: markedBy || this.getCurrentUser(),
markedAt: markedAt || new Date().toISOString(),
status: 'pending' // pending, approved, rejected, removed
};
this.markers.set(markerId, marker);
this.addInlineComment(filePath, lineStart, this.generateMarkerComment(marker));
return markerId;
}
/**
* 生成标记注释
* @param {Object} marker - 标记对象
* @returns {string} 注释内容
*/
generateMarkerComment(marker) {
const comments = [
`@deprecated ${marker.reason}`,
`@marker-type ${marker.type}`,
`@marked-by ${marker.markedBy}`,
`@marked-at ${marker.markedAt}`
];
if (marker.replacement) {
comments.push(`@replacement ${marker.replacement}`);
}
if (marker.type === this.markerTypes.DEPRECATED) {
comments.push('@todo Remove in next major version');
}
return comments.join('\n * ');
}
/**
* 在代码中添加内联注释
* @param {string} filePath - 文件路径
* @param {number} lineNumber - 行号
* @param {string} comment - 注释内容
*/
addInlineComment(filePath, lineNumber, comment) {
const fileContent = this.readFile(filePath);
const lines = fileContent.split('\n');
// 在指定行前添加注释
const commentBlock = [
'/**',
` * ${comment}`,
' */'
].join('\n');
lines.splice(lineNumber - 1, 0, commentBlock);
this.writeFile(filePath, lines.join('\n'));
}
/**
* 批量标记文件中的导出
* @param {string} filePath - 文件路径
* @param {Array} exports - 导出列表
* @param {Object} options - 标记选项
*/
markExports(filePath, exports, options) {
const fileContent = this.readFile(filePath);
const lines = fileContent.split('\n');
exports.forEach(exp => {
const exportLine = this.findExportLine(lines, exp);
if (exportLine !== -1) {
this.markCode({
...options,
filePath,
lineStart: exportLine,
lineEnd: exportLine
});
}
});
}
/**
* 查找导出语句所在的行号
* @param {Array} lines - 代码行数组
* @param {string} exportName - 导出名称
* @returns {number} 行号,未找到返回-1
*/
findExportLine(lines, exportName) {
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// 匹配各种导出模式
if (
line.includes(`export ${exportName}`) ||
line.includes(`export { ${exportName}`) ||
line.includes(`export {.*${exportName}.*}`) ||
line.includes(`export default ${exportName}`)
) {
return i + 1; // 行号从1开始
}
}
return -1;
}
/**
* 获取特定状态的标记
* @param {string} status - 状态
* @returns {Array} 标记列表
*/
getMarkersByStatus(status) {
return Array.from(this.markers.values())
.filter(marker => marker.status === status);
}
/**
* 更新标记状态
* @param {string} markerId - 标记ID
* @param {string} status - 新状态
* @param {string} reviewedBy - 审核人
*/
updateMarkerStatus(markerId, status, reviewedBy) {
if (this.markers.has(markerId)) {
const marker = this.markers.get(markerId);
marker.status = status;
marker.reviewedBy = reviewedBy;
marker.reviewedAt = new Date().toISOString();
}
}
}
使用示例:
const marker = new CodeMarker();
// 标记废弃的函数
marker.markCode({
filePath: 'src/utils/helpers.js',
lineStart: 15,
lineEnd: 25,
type: marker.markerTypes.DEPRECATED,
reason: 'Replaced by new implementation with better performance',
replacement: 'use newHelperFunction instead',
markedBy: 'john.doe'
});
// 批量标记未使用的导出
marker.markExports(
'src/components/LegacyComponents.js',
['OldComponentA', 'OldComponentB'],
{
type: marker.markerTypes.UNUSED,
reason: 'Components are no longer used in the application',
markedBy: 'jane.smith'
}
);
架构解析: 这是一个代码标记系统,用于在代码中添加标记注释并跟踪标记状态。
设计思路: 通过在代码中添加结构化注释,明确标识可疑代码,并通过状态管理跟踪清理进度。
重点逻辑:
参数解析:
markers
: 存储所有标记的Map。markerTypes
: 标记类型枚举。options
: 标记配置选项。filePath
: 被标记的文件路径。lineStart/lineEnd
: 标记的代码行范围。// 代码墓碑系统
class CodeTombstone {
constructor() {
this.tombstones = new Map(); // 存储墓碑记录
this.tombstoneDir = '.tombstones'; // 墓碑文件存储目录
}
/**
* 为即将删除的代码创建墓碑
* @param {Object} codeInfo - 代码信息
* @returns {string} 墓碑ID
*/
createTombstone(codeInfo) {
const {
filePath,
codeSnippet,
deletionReason,
deprecatedSince,
createdBy,
relatedIssues
} = codeInfo;
const tombstoneId = this.generateTombstoneId(filePath);
const tombstone = {
id: tombstoneId,
filePath,
fileName: this.getFileName(filePath),
codeSnippet: this.extractCodeSnippet(codeSnippet),
deletionReason,
deprecatedSince: deprecatedSince || new Date().toISOString(),
createdAt: new Date().toISOString(),
createdBy: createdBy || this.getCurrentUser(),
relatedIssues: relatedIssues || [],
status: 'pending', // pending, approved, deleted
backupPath: this.createBackup(codeSnippet, tombstoneId)
};
this.tombstones.set(tombstoneId, tombstone);
this.saveTombstoneToFile(tombstone);
return tombstoneId;
}
/**
* 生成墓碑ID
* @param {string} filePath - 文件路径
* @returns {string} 墓碑ID
*/
generateTombstoneId(filePath) {
const fileName = this.getFileName(filePath);
const timestamp = Date.now();
return `${fileName}_${timestamp}`;
}
/**
* 提取文件名
* @param {string} filePath - 文件路径
* @returns {string} 文件名
*/
getFileName(filePath) {
return filePath.split('/').pop().split('.')[0];
}
/**
* 提取代码片段摘要
* @param {string} code - 代码内容
* @returns {string} 代码摘要
*/
extractCodeSnippet(code) {
// 提取代码的前几行作为摘要
const lines = code.split('\n');
const summaryLines = lines.slice(0, 5);
return {
full: code,
summary: summaryLines.join('\n'),
lineCount: lines.length
};
}
/**
* 创建代码备份
* @param {string} code - 代码内容
* @param {string} tombstoneId - 墓碑ID
* @returns {string} 备份文件路径
*/
createBackup(code, tombstoneId) {
const backupPath = `${this.tombstoneDir}/backups/${tombstoneId}.backup.js`;
this.writeFile(backupPath, code);
return backupPath;
}
/**
* 保存墓碑记录到文件
* @param {Object} tombstone - 墓碑对象
*/
saveTombstoneToFile(tombstone) {
const tombstonePath = `${this.tombstoneDir}/records/${tombstone.id}.json`;
this.writeFile(tombstonePath, JSON.stringify(tombstone, null, 2));
}
/**
* 获取墓碑记录
* @param {string} tombstoneId - 墓碑ID
* @returns {Object} 墓碑对象
*/
getTombstone(tombstoneId) {
if (this.tombstones.has(tombstoneId)) {
return this.tombstones.get(tombstoneId);
}
// 从文件系统加载
const tombstonePath = `${this.tombstoneDir}/records/${tombstoneId}.json`;
if (this.fileExists(tombstonePath)) {
const content = this.readFile(tombstonePath);
const tombstone = JSON.parse(content);
this.tombstones.set(tombstoneId, tombstone);
return tombstone;
}
return null;
}
/**
* 列出所有墓碑
* @param {Object} filter - 过滤条件
* @returns {Array} 墓碑列表
*/
listTombstones(filter = {}) {
let tombstones = Array.from(this.tombstones.values());
// 应用过滤条件
if (filter.status) {
tombstones = tombstones.filter(t => t.status === filter.status);
}
if (filter.createdBy) {
tombstones = tombstones.filter(t => t.createdBy === filter.createdBy);
}
if (filter.dateRange) {
const { start, end } = filter.dateRange;
tombstones = tombstones.filter(t => {
const createdAt = new Date(t.createdAt);
return createdAt >= start && createdAt <= end;
});
}
return tombstones;
}
/**
* 批准墓碑(准备删除)
* @param {string} tombstoneId - 墓碑ID
* @param {string} approvedBy - 批准人
*/
approveTombstone(tombstoneId, approvedBy) {
const tombstone = this.getTombstone(tombstoneId);
if (tombstone) {
tombstone.status = 'approved';
tombstone.approvedBy = approvedBy;
tombstone.approvedAt = new Date().toISOString();
this.saveTombstoneToFile(tombstone);
}
}
/**
* 恢复已删除的代码
* @param {string} tombstoneId - 墓碑ID
* @returns {boolean} 是否恢复成功
*/
restoreCode(tombstoneId) {
const tombstone = this.getTombstone(tombstoneId);
if (!tombstone || tombstone.status !== 'deleted') {
return false;
}
try {
const backupContent = this.readFile(tombstone.backupPath);
this.writeFile(tombstone.filePath, backupContent);
tombstone.status = 'restored';
tombstone.restoredAt = new Date().toISOString();
this.saveTombstoneToFile(tombstone);
return true;
} catch (error) {
console.error('Failed to restore code:', error);
return false;
}
}
/**
* 生成墓碑报告
* @param {Object} options - 报告选项
* @returns {string} 报告内容
*/
generateReport(options = {}) {
const tombstones = this.listTombstones(options.filter || {});
const report = {
generatedAt: new Date().toISOString(),
total: tombstones.length,
byStatus: this.groupBy(tombstones, 'status'),
byCreator: this.groupBy(tombstones, 'createdBy'),
byReason: this.groupBy(tombstones, 'deletionReason'),
recent: tombstones
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
.slice(0, 10)
};
return report;
}
/**
* 按属性分组
* @param {Array} array - 数组
* @param {string} key - 分组键
* @returns {Object} 分组结果
*/
groupBy(array, key) {
return array.reduce((result, item) => {
const groupKey = item[key];
if (!result[groupKey]) {
result[groupKey] = [];
}
result[groupKey].push(item);
return result;
}, {});
}
}
使用示例:
const tombstone = new CodeTombstone();
// 为废弃组件创建墓碑
tombstone.createTombstone({
filePath: 'src/components/LegacyChart.js',
codeSnippet: legacyChartCode,
deletionReason: 'Replaced by new charting library',
deprecatedSince: '2023-06-01',
createdBy: 'john.doe',
relatedIssues: ['#1234', '#5678']
});
// 批准删除
tombstone.approveTombstone('LegacyChart_1689876543210', 'jane.smith');
// 生成报告
const report = tombstone.generateReport({
filter: {
status: 'approved',
dateRange: {
start: new Date('2023-07-01'),
end: new Date()
}
}
});
架构解析: 代码墓碑系统,用于记录即将删除的代码信息并提供恢复机制。
设计思路: 通过创建墓碑记录,保存被删除代码的完整信息和备份,确保在需要时可以恢复。
重点逻辑:
参数解析:
tombstones
: 存储墓碑记录的Map。tombstoneDir
: 墓碑文件存储目录。codeInfo
: 被删除代码的信息。tombstoneId
: 墓碑唯一标识符。四阶段移除法:
配套工具:
// scripts/removeDeadCode.js
const { execSync } = require('child_process');
const fs = require('fs');
function safeRemove(filePath) {
try {
// 1. 检查git历史
const lastEdit = execSync(`git log -1 --format="%ai" -- ${filePath}`).toString();
// 2. 检查引用
const refs = execSync(`grep -r "${filePath}" src/`).toString();
if (!refs.trim()) {
// 3. 创建备份
fs.copyFileSync(filePath, `archive/${filePath}`);
// 4. 实际删除
fs.unlinkSync(filePath);
console.log(`✅ 安全删除: ${filePath}`);
} else {
console.log(`⚠️ 存在引用: ${filePath}`);
}
} catch (error) {
console.error(`❌ 删除失败: ${filePath}`, error);
}
}
CI/CD集成:
# .github/workflows/code-cleanup.yml
name: Code Cleanup Check
on:
schedule:
- cron: '0 0 * * 1' # 每周一运行
pull_request:
paths:
- 'src/**'
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm install
- run: npm run analyze
- name: Check for dead code
run: |
DEAD_FILES=$(ts-prune | grep -v 'used in module')
if [ -n "$DEAD_FILES" ]; then
echo "::warning::发现未使用代码: $DEAD_FILES"
exit 1
fi
架构决策记录模板:
# ADR-042: 移除旧版表单系统
## 状态
✅ 已批准
## 背景
自v5.0.0引入新的Formik集成后,旧版表单...
## 决策
- 在v5.3.0标记为废弃
- 计划在v6.0.0完全移除
- 提供迁移工具`formMigrator.js`
## 影响
- 需要更新15个页面的表单
- 影响3个自定义表单控件
- 减少打包体积约23KB
建立有效的代码清理最佳实践,确保整个流程的可持续性和可靠性。
// 时间窗口管理器
class TimeWindowManager {
constructor() {
this.windows = new Map();
}
/**
* 创建时间窗口
* @param {string} name - 窗口名称
* @param {Object} config - 配置
*/
createTimeWindow(name, config) {
const {
retentionPeriod = '30d', // 保留期
warningPeriod = '7d', // 警告期
gracePeriod = '3d', // 宽限期
reviewRequired = true // 是否需要审核
} = config;
const window = {
name,
retentionPeriod: this.parseDuration(retentionPeriod),
warningPeriod: this.parseDuration(warningPeriod),
gracePeriod: this.parseDuration(gracePeriod),
reviewRequired,
createdAt: new Date().toISOString(),
items: new Set()
};
this.windows.set(name, window);
return window;
}
/**
* 将项目添加到时间窗口
* @param {string} windowName - 窗口名称
* @param {Object} item - 项目
*/
addItem(windowName, item) {
const window = this.windows.get(windowName);
if (!window) {
throw new Error(`Time window ${windowName} not found`);
}
const windowItem = {
...item,
addedAt: new Date().toISOString(),
status: 'pending',
eligibleForRemovalAt: this.calculateEligibleDate(window, item)
};
window.items.add(windowItem);
return windowItem;
}
/**
* 计算可移除日期
* @param {Object} window - 时间窗口
* @param {Object} item - 项目
* @returns {string} 可移除日期ISO字符串
*/
calculateEligibleDate(window, item) {
const addedAt = new Date(item.addedAt || new Date());
const eligibleDate = new Date(addedAt);
eligibleDate.setDate(eligibleDate.getDate() + window.retentionPeriod);
return eligibleDate.toISOString();
}
/**
* 检查项目是否可以移除
* @param {string} windowName - 窗口名称
* @param {Object} item - 项目
* @returns {Object} 检查结果
*/
checkRemovalEligibility(windowName, item) {
const window = this.windows.get(windowName);
if (!window) {
return { eligible: false, reason: 'Window not found' };
}
const now = new Date();
const eligibleDate = new Date(item.eligibleForRemovalAt);
if (now < eligibleDate) {
const daysLeft = Math.ceil((eligibleDate - now) / (1000 * 60 * 60 * 24));
return {
eligible: false,
reason: `Retention period not expired (${daysLeft} days left)`
};
}
// 检查是否在警告期内
const warningEndDate = new Date(eligibleDate);
warningEndDate.setDate(warningEndDate.getDate() + window.warningPeriod);
if (now < warningEndDate) {
return {
eligible: false,
reason: 'In warning period - manual review required',
warning: true
};
}
// 检查是否在宽限期内
const graceEndDate = new Date(warningEndDate);
graceEndDate.setDate(graceEndDate.getDate() + window.gracePeriod);
if (now < graceEndDate) {
return {
eligible: true,
gracePeriod: true,
message: 'In grace period - proceed with caution'
};
}
return { eligible: true, message: 'Eligible for removal' };
}
/**
* 获取可移除的项目
* @param {string} windowName - 窗口名称
* @returns {Array} 可移除项目列表
*/
getEligibleItems(windowName) {
const window = this.windows.get(windowName);
if (!window) return [];
const now = new Date();
const eligibleItems = [];
for (const item of window.items) {
const checkResult = this.checkRemovalEligibility(windowName, item);
if (checkResult.eligible) {
eligibleItems.push({
item,
checkResult
});
}
}
return eligibleItems;
}
/**
* 解析持续时间
* @param {string} duration - 持续时间字符串
* @returns {number} 天数
*/
parseDuration(duration) {
const match = duration.match(/^(\d+)([dwm])$/);
if (!match) {
throw new Error(`Invalid duration format: ${duration}`);
}
const value = parseInt(match[1]);
const unit = match[2];
switch (unit) {
case 'd': return value;
case 'w': return value * 7;
case 'm': return value * 30;
default: throw new Error(`Unknown time unit: ${unit}`);
}
}
/**
* 生成时间窗口报告
* @param {string} windowName - 窗口名称
* @returns {Object} 报告
*/
generateReport(windowName) {
const window = this.windows.get(windowName);
if (!window) return null;
const now = new Date();
const report = {
windowName,
generatedAt: now.toISOString(),
totalItems: window.items.size,
byStatus: {},
byEligibility: {
eligible: 0,
notEligible: 0,
warningPeriod: 0,
gracePeriod: 0
}
};
for (const item of window.items) {
// 按状态统计
if (!report.byStatus[item.status]) {
report.byStatus[item.status] = 0;
}
report.byStatus[item.status]++;
// 按可移除性统计
const eligibility = this.checkRemovalEligibility(windowName, item);
if (eligibility.eligible) {
if (eligibility.gracePeriod) {
report.byEligibility.gracePeriod++;
} else {
report.byEligibility.eligible++;
}
} else {
if (eligibility.warning) {
report.byEligibility.warningPeriod++;
} else {
report.byEligibility.notEligible++;
}
}
}
return report;
}
}
// 使用示例
const timeWindowManager = new TimeWindowManager();
// 创建标准清理窗口
timeWindowManager.createTimeWindow('standard-cleanup', {
retentionPeriod: '30d',
warningPeriod: '7d',
gracePeriod: '3d',
reviewRequired: true
});
// 添加待清理项目
timeWindowManager.addItem('standard-cleanup', {
id: 'legacy-component-123',
type: 'component',
filePath: 'src/components/LegacyComponent.js',
reason: 'Replaced by new implementation'
});
// 检查可移除性
const eligibility = timeWindowManager.checkRemovalEligibility(
'standard-cleanup',
{ id: 'legacy-component-123' }
);
console.log('Removal eligibility:', eligibility);
架构解析: 这是一个时间窗口管理器,用于管理代码清理的时间策略。
设计思路: 通过设置不同的时间阶段(保留期、警告期、宽限期),确保代码在被移除前有足够的时间进行验证。
重点逻辑:
参数解析:
windows
: 存储时间窗口的Map。retentionPeriod
: 保留期(天数)。warningPeriod
: 警告期(天数)。gracePeriod
: 宽限期(天数)。const { appendFileSync, readFileSync } = require('fs');
/**
* 更新变更日志和类型定义文件,标记组件为已弃用
* @param {Object} deprecation - 弃用信息对象
* @param {string} deprecation.component - 被弃用的组件名称
* @param {string} [deprecation.alternative] - 替代方案
* @param {string} deprecation.removeAfter - 计划移除时间
* @returns {void}
*/
function updateChangelog(deprecation) {
const entry = `\n## ${new Date().toISOString().split('T')[0]}
- Deprecated: ${deprecation.component}
- Alternative: ${deprecation.alternative || 'None'}
- Removal planned: ${deprecation.removeAfter}\n`;
appendFileSync('CHANGELOG.md', entry);
// 更新类型定义
const types = readFileSync('types.d.ts', 'utf8');
const updated = types.replace(`interface ${deprecation.component}`, `/** @deprecated */\ninterface ${deprecation.component}`);
writeFileSync('types.d.ts', updated);
}
同步策略:
在项目废弃某个组件时,自动更新项目的文档和类型定义,确保:
功能解析:
fs
模块中导入三个同步文件操作方法:appendFileSync
: 向文件末尾追加内容。readFileSync
: 同步读取文件内容。writeFileSync
: 同步写入文件内容。deprecation
对象作为参数,该对象包含以下属性:component
: 被废弃的组件/接口名称。alternative
: 替代方案(可选)。removeAfter
: 计划移除的时间。/** @deprecated */
的JSDoc注释。站会提醒模板:
**代码清理通知** 📢
即将移除的组件:
- `OldModal` (替换为 `NewDialog`)
- 影响文件:8处
- 最后使用:2023-11-15
- 移除日期:2023-12-01
需要行动:
1. 检查你的功能分支
2. 更新测试用例
3. 报告任何问题
通过本文的系统化方法,我们建立了从代码发现到安全移除的完整生命周期管理:
好的代码清理不是一次性任务,而是持续的质量实践。
建议将本文方法集成到日常开发流程中,定期执行"代码卫生检查",保持代码库的健康状态。当每个团队成员都具备代码清理意识时,项目就能在快速迭代中维持长期的可维护性。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。