首页 › tutorials › Claude Code大规模重构与架构迁移实战

Claude Code大规模重构与架构迁移实战

概述

本教程面向有6个月以上Claude Code使用经验的中高级开发者,聚焦如何利用Claude Code的上下文工程、多文件编辑、Workflow编排等核心能力,安全高效地完成大规模代码重构和架构迁移任务。学完本教程,你将掌握从重构规划、增量迁移到质量守卫的完整方法论,能够在真实项目中用Claude Code完成万行级代码的架构升级。

前置条件


一、大规模重构的核心挑战与Claude Code的解法

1.1 为什么传统重构方式效率低下

大规模重构面临三个核心痛点:

痛点 具体表现 传统解法成本
影响范围不可控 一个接口改动影响50+个文件,手动排查遗漏率高 需要全局搜索+人工判断
上下文窗口有限 人脑无法同时持有数千行代码的完整认知 反复跳转文件,效率断崖式下降
回归风险高 重构引入隐蔽bug,测试覆盖不足时难以发现 需要大量手工测试

Claude Code的独特优势在于:它能同时持有数千行代码的上下文,理解跨文件的语义依赖关系,并通过Workflow编排实现"理解→规划→执行→验证"的闭环。

1.2 重构决策矩阵

在开始前,用以下矩阵判断你的重构是否适合交给Claude Code:

重构适合度评分 = (文件变更数 × 2) + (模式一致性 × 3) + (测试覆盖率 × 2) - (业务逻辑复杂度 × 2)

- 文件变更数 > 20:+高分(批量操作是Claude Code强项)
- 模式一致性高(同样的改动模式重复出现):+高分
- 测试覆盖率 > 60%:+高分(有安全网)
- 业务逻辑复杂(需要深度领域知识):-高分(需人工参与决策)

适合Claude Code的重构场景: - 框架升级(React 18→19、Next.js 13→15) - API版本迁移(REST→GraphQL、v1→v2) - 设计模式统一(统一错误处理、统一日志格式) - 语言特性迁移(JavaScript→TypeScript、Class→Hooks) - 依赖清理与替换

不适合纯Claude Code的场景: - 需要与产品经理确认的业务逻辑变更 - 涉及数据库Schema的重大变更(需DBA审核) - 安全敏感的认证授权流程重构


二、重构前的情报收集——用Claude Code绘制代码地图

2.1 启动情报收集会话

重构的第一步不是写代码,而是理解现状。用Claude Code的非交互模式快速扫描项目:

# 第一步:生成项目结构概览
claude -p "分析当前项目的目录结构和架构模式,输出:
1. 主要模块及其职责
2. 模块间的依赖关系(用列表表示)
3. 识别出可能的循环依赖
4. 外部依赖清单(package.json或requirements.txt中的关键依赖)

格式要求:每个模块用3-5句话描述,依赖关系用A→B的格式" \
  --allowedTools "Read,Glob,Grep" > project-analysis.md

预期输出(示例):

## 项目结构分析

### 模块清单
1. `src/api/` - REST API层,包含用户、订单、商品三个子模块
   - 职责:HTTP请求处理、参数验证、响应序列化
   - 问题:部分业务逻辑泄露到Controller中

2. `src/services/` - 业务逻辑层
   - 职责:核心业务规则、数据编排
   - 问题:与API层存在双向依赖

### 依赖关系
src/api → src/services → src/repositories → src/models
src/api → src/utils(循环:src/utils → src/api)

### 循环依赖警告
- src/utils/httpClient.ts 导入了 src/api/interceptors.ts
- 建议将 interceptors 提取为独立模块

2.2 精确定位变更影响范围

假设我们要将项目从Express迁移到Fastify,首先确定影响范围:

# 搜索所有Express特有的API调用
claude -p "搜索整个项目中所有使用Express特有API的位置,包括但不限于:
- express() 应用创建
- req/res 对象的Express特有方法
- express.Router()
- express中间件(bodyParser, cors等)
- 错误处理中间件 (err, req, res, next) 四参数模式

输出格式:文件路径:行号 | 具体代码 | Express API | Fastify等价写法建议" \
  --allowedTools "Grep,Read,Glob"

2.3 生成依赖热力图

利用Claude Code的Grep能力统计每个文件的被引用次数:

# 找出被最多文件引用的模块(高风险变更点)
claude -p "统计src/目录下所有TypeScript/JavaScript文件的被导入次数。
对每个文件,计算有多少其他文件导入了它。
按被导入次数降序排列,输出前30个文件。
标注被导入超过10次的文件为[HIGH RISK]。" \
  --allowedTools "Grep,Read,Glob"

2.4 建立重构基线

在动手之前,确保有安全网:

# 1. 创建重构专用分支
git checkout -b refactor/express-to-fastify

# 2. 确保测试通过
claude -p "运行项目的完整测试套件,记录当前测试结果。
如果有失败的测试,分析原因并输出修复建议。
最终输出:总测试数、通过数、失败数、跳过数" \
  --allowedTools "Bash"

# 3. 创建CLAUDE.md记录重构计划
# 在项目根目录的CLAUDE.md中添加重构上下文

在项目的 CLAUDE.md 中记录重构元信息:

## 当前重构任务

### 目标
将Web框架从Express 4.x迁移到Fastify 5.x

### 约束
- 保持所有现有API端点的行为不变
- 必须通过所有现有测试
- 增量迁移,每个PR不超过500行变更
- 中间件迁移优先级:认证 > 日志 > 错误处理 > 其他

### 进度追踪
- [ ] Phase 1: 基础设施层(应用创建、配置加载)
- [ ] Phase 2: 中间件迁移(按优先级顺序)
- [ ] Phase 3: 路由注册方式迁移
- [ ] Phase 4: 请求/响应处理方式适配
- [ ] Phase 5: 错误处理统一
- [ ] Phase 6: 测试适配与验证

### 风险点
- Express的(req, res, next)签名需改为Fastify的(request, reply)签名
- 第三方中间件可能没有Fastify等价物
- 文件上传处理方式完全不同

三、规划阶段——用EnterPlanMode制定迁移策略

3.1 进入计划模式

Claude Code的Plan Mode是大规模重构的利器。当你给它一个复杂的重构任务时,它不会直接开始改代码,而是先输出完整的执行计划供你审核:

> 我需要将这个Express项目迁移到Fastify。请先制定详细的迁移计划,
> 覆盖所有src/目录下的文件。要求:
> 1. 按模块分批次,每批变更不超过10个文件
> 2. 每批变更后测试应全部通过
> 3. 标注每批变更的风险等级(低/中/高)

Claude Code会进入Plan Mode,读取项目文件,分析依赖关系,然后输出类似这样的计划:

## 迁移计划:Express → Fastify

### Phase 1: 基础设施 [风险:低]
变更文件:3个
- src/app.ts: 替换express()为fastify()
- src/server.ts: 更新启动逻辑
- src/config/index.ts: 添加Fastify配置项

### Phase 2: 错误处理中间件 [风险:中]
变更文件:5个
- src/middleware/errorHandler.ts: 重写为Fastify插件
- src/middleware/notFound.ts: 迁移到Fastify 404处理
- src/api/users/index.ts: 错误处理适配
- src/api/orders/index.ts: 错误处理适配
- src/api/products/index.ts: 错误处理适配

### Phase 3-6: [后续阶段...]

### 执行顺序依赖图
Phase 1 → Phase 2 → Phase 3(依赖Phase 1的应用实例)
                    → Phase 4(可与Phase 3并行)
         Phase 5 → Phase 6(最终验证)

3.2 审核与调整计划

计划输出后,你可以:

# 调整计划的执行顺序
> 将Phase 3和Phase 4的执行顺序对调,因为路由注册更关键

# 给特定阶段增加约束
> Phase 2中,errorHandler需要同时支持新旧格式,方便回滚

# 拆分过大的阶段
> Phase 3涉及的文件太多,按api子模块拆成3a/3b/3c三个子阶段

3.3 工作流程图

以下是完整的重构工作流程:

flowchart TD
    A[启动重构任务] --> B[情报收集阶段]
    B --> B1[项目结构分析]
    B --> B2[依赖热力图]
    B --> B3[变更影响范围]
    B --> B4[测试基线建立]

    B1 & B2 & B3 & B4 --> C[规划阶段<br/>EnterPlanMode]
    C --> C1[生成分批迁移计划]
    C --> C2[人工审核调整]
    C --> C3[记录到CLAUDE.md]

    C1 & C2 & C3 --> D[执行阶段]
    D --> D1[Phase N: 批量文件修改]
    D1 --> D2[运行测试验证]
    D2 --> D3{测试通过?}
    D3 -->|是| D4[Git提交]
    D3 -->|否| D5[Claude Code自动修复]
    D5 --> D2
    D4 --> D6{还有更多Phase?}
    D6 -->|是| D1
    D6 -->|否| E[最终验证阶段]

    E --> E1[全量测试]
    E --> E2[性能基准对比]
    E --> E3[代码审查]
    E1 & E2 & E3 --> F[合并到主分支]

    style B fill:#e1f5fe
    style C fill:#fff3e0
    style D fill:#e8f5e9
    style E fill:#fce4ec
    style F fill:#f3e5f5

四、执行阶段——增量迁移的六步法

4.1 Step 1: 创建适配层(Bridge Pattern)

大规模迁移的核心策略是适配层模式:先建桥,再迁移,最后拆桥。

# 让Claude Code创建适配层
> 请在src/adapters/目录下创建一个ExpressToFastify适配层,包含:
> 1. expressToFastifyMiddleware.ts - 将Express中间件包装为Fastify插件
> 2. expressToFastifyHandler.ts - 将(req,res,next)处理器转换为(request,reply)
> 3. expressToFastifyRouter.ts - 将Express Router映射为Fastify路由
> 
> 这些适配器应该:
> - 保持原有函数签名不变
> - 内部使用Fastify API
> - 添加@deprecated JSDoc注释
> - 包含完整的TypeScript类型定义

生成的适配器示例(src/adapters/expressToFastifyHandler.ts):

import { FastifyRequest, FastifyReply } from 'fastify';
import { Request, Response, NextFunction } from 'express';

type ExpressHandler = (
  req: Request,
  res: Response,
  next: NextFunction
) => void | Promise<void>;

/**
 * @deprecated 仅用于Express→Fastify迁移过渡期
 * 将Express风格的请求处理器适配为Fastify风格
 */
export function adaptHandler(handler: ExpressHandler) {
  return async (request: FastifyRequest, reply: FastifyReply) => {
    // 映射Express req → Fastify request
    const expressReq = mapToExpressRequest(request);
    const expressRes = mapToExpressResponse(reply);

    try {
      await handler(expressReq, expressRes, () => {});
    } catch (error) {
      reply.status(500).send({ error: 'Internal Server Error' });
    }
  };
}

4.2 Step 2: 逐模块迁移——利用TaskList追踪进度

使用Claude Code的任务列表功能追踪迁移进度:

> 请创建以下任务列表来追踪Fastify迁移进度:
> 
> 1. [ ] 迁移 src/app.ts - 替换框架创建逻辑
> 2. [ ] 迁移 src/middleware/auth.ts - JWT认证中间件
> 3. [ ] 迁移 src/middleware/logger.ts - 请求日志中间件  
> 4. [ ] 迁移 src/api/users/ - 用户模块路由
> 5. [ ] 迁移 src/api/orders/ - 订单模块路由
> 6. [ ] 迁移 src/api/products/ - 商品模块路由
> 7. [ ] 迁移 src/middleware/errorHandler.ts - 全局错误处理
> 8. [ ] 更新所有测试文件
> 9. [ ] 删除适配层
> 10. [ ] 最终全量验证
> 
> 任务依赖关系:1→2,3; 2,3→4,5,6; 4,5,6→7; 7→8; 8→9; 9→10

4.3 Step 3: 执行单模块迁移

对每个模块,使用Claude Code的Plan Mode确保安全:

> 现在开始执行任务1:迁移 src/app.ts
> 
> 要求:
> 1. 先读取当前文件内容
> 2. 识别所有Express特有API
> 3. 用Fastify等价API替换
> 4. 保持所有导出接口不变
> 5. 运行测试验证

Claude Code的典型执行流程:

[读取] src/app.ts(45行)
[分析] 识别到3个Express特有调用:
  - Line 5: const app = express()
  - Line 12: app.use(express.json())
  - Line 25: app.listen(port, callback)

[修改] 执行替换:
  - express() → fastify({ logger: true })
  - app.use(express.json()) → 已内置,删除
  - app.listen() → app.listen({ port, host })

[验证] 运行 npm test
  ✓ 23 tests passed
  ✓ 0 tests failed

[标记] 任务1完成 ✓

4.4 Step 4: 批量模式迁移——利用Workflow编排

当模式一致时(如所有Controller都需要同样的签名变更),使用Workflow进行批量处理:

> 所有API路由文件都有相同的签名变更需求:
> 将 (req: Request, res: Response, next: NextFunction) 
> 改为 (request: FastifyRequest, reply: FastifyReply)
> 
> 请用批量方式处理 src/api/ 下的所有路由文件。
> 每个文件处理完后运行该模块的测试。
> 如果测试失败,自动回滚该文件的修改并报告问题。

Workflow编排自动执行:

flowchart LR
    subgraph "并行处理模块"
        M1[users路由<br/>3个文件] --> T1[运行users测试]
        M2[orders路由<br/>4个文件] --> T2[运行orders测试]
        M3[products路由<br/>2个文件] --> T3[运行products测试]
    end

    T1 --> R1{通过?}
    T2 --> R2{通过?}
    T3 --> R3{通过?}

    R1 -->|是| C1[提交 ✓]
    R1 -->|否| F1[回滚并报告]
    R2 -->|是| C2[提交 ✓]
    R2 -->|否| F2[回滚并报告]
    R3 -->|是| C3[提交 ✓]
    R3 -->|否| F3[回滚并报告]

    C1 & C2 & C3 --> S[汇总结果]
    F1 & F2 & F3 --> S

4.5 Step 5: 处理棘手的迁移场景

场景A:第三方中间件没有Fastify等价物

> 我发现项目使用了express-fileupload中间件,Fastify没有直接等价物。
> 请研究:
> 1. Fastify生态中最接近的替代品是什么
> 2. 提供两种方案:a) 使用Fastify原生multipart b) 通过适配层包装原中间件
> 3. 列出每种方案的pros/cons
> 4. 推荐一种方案并给出实现代码

场景B:渐进式共存——Express和Fastify同时运行

在某些大型项目中,不可能一次性切换框架。使用代理模式实现共存:

// src/adapters/dualFramework.ts
// Express和Fastify共存的桥接层

import express from 'express';
import fastify from 'fastify';

export class DualFrameworkApp {
  private expressApp = express();
  private fastifyApp = fastify();

  // 已迁移的路由走Fastify
  private migratedRoutes = new Set<string>();

  async handleRequest(req: any, res: any) {
    const routeKey = `${req.method}:${req.route?.path}`;

    if (this.migratedRoutes.has(routeKey)) {
      // 转发给Fastify处理
      await this.fastifyApp.inject({
        method: req.method,
        url: req.url,
        payload: req.body,
      });
    } else {
      // 仍由Express处理
      this.expressApp(req, res);
    }
  }

  markMigrated(method: string, path: string) {
    this.migratedRoutes.add(`${method}:${path}`);
  }
}

4.6 Step 6: 验证与收尾

# 全面验证
claude -p "执行最终验证:
1. 运行完整测试套件,确保100%通过
2. 搜索整个项目,确认没有残留的express导入
3. 检查所有TypeScript类型是否正确
4. 对比迁移前后的API响应格式,确认兼容
5. 输出最终的变更统计:文件数、行数、删除/新增

如有任何问题,输出详细的问题报告和修复建议。" \
  --allowedTools "Bash,Grep,Read,Glob"

五、高级技巧——让Claude Code成为重构利器

5.1 利用记忆系统维护重构上下文

跨会话的大型重构中,Claude Code的记忆系统(Memory)是防止上下文丢失的关键:

> 请记住以下重构上下文到你的记忆文件中:
> 
> 项目:ecommerce-api
> 当前重构:Express → Fastify迁移
> 已完成阶段:Phase 1-3
> 当前阶段:Phase 4(路由适配)
> 剩余工作:Phase 5-6
> 
> 关键决策记录:
> - 决定使用@fastify/multipart替代express-fileupload
> - 错误处理采用Fastify的setErrorHandler而非中间件
> - 暂时保留适配层,Phase 6统一删除
> 
> 已知问题:
> - orders模块的文件上传功能需要在Phase 5特殊处理
> - tests/fixtures/中的mock对象仍使用Express类型

这样在下次会话中,Claude Code会自动加载这些上下文:

# 新会话中继续重构
claude

> 继续Fastify迁移,从上次停下的Phase 4开始
# Claude Code会从记忆中恢复上下文,无缝继续

5.2 使用CLAUDE.md建立项目级重构规则

在项目的 .claude/ 目录下创建 CLAUDE.md,为Claude Code提供持久化的重构指导:

# 项目重构指南

## 架构约束
- Web框架:Fastify 5.x(迁移中,部分模块仍用Express)
- 禁止新增Express依赖
- 新代码必须使用Fastify API
- 所有新中间件必须是Fastify插件格式

## 迁移编码规范
- 路由处理器签名:(request: FastifyRequest, reply: FastifyReply) => Promise<void>
- 错误抛出:使用 reply.status(code).send({error}) 而非 throw
- 请求体访问:request.body(不是req.body)
- 查询参数:request.query(不是req.query)
- 路径参数:request.params(不是req.params)

## 测试要求
- 每个迁移的模块必须有对应的集成测试
- 测试使用 supertest 或 Fastify的 inject() 方法
- 迁移前后的测试用例必须保持一致

## 文件命名
- 适配器文件放在 src/adapters/
- 已迁移的文件顶部添加注释:// Migrated to Fastify

5.3 用Hooks自动化重构质量检查

在 .claude/settings.json 中配置Hooks,在每次代码修改后自动运行质量检查:

{
  "hooks": {
    "afterEdit": [
      {
        "matcher": "src/**/*.ts",
        "command": "npx tsc --noEmit --pretty 2>&1 | head -20",
        "description": "TypeScript类型检查"
      }
    ],
    "afterWrite": [
      {
        "matcher": "src/**/*.ts",
        "command": "npx eslint ${FILE} --max-warnings=0 2>&1 | tail -5",
        "description": "ESLint检查修改的文件"
      }
    ]
  }
}

5.4 上下文窗口管理策略

大规模重构时,上下文窗口是最宝贵的资源。以下是优化策略:

策略一:分而治之

# 不要一次性处理整个项目,按模块分解
# 错误示范:
claude -p "把整个项目从Express迁移到Fastify"  # 上下文会爆

# 正确做法:
claude -p "只迁移 src/middleware/auth.ts 到 Fastify,不要修改其他文件"

策略二:利用Grep减少读取量

# 让Claude Code用Grep定位而非读取整个文件
claude -p "找到所有使用了express.Router()的文件,
列出文件路径和行号即可,不要读取文件内容" \
  --allowedTools "Grep,Glob"

策略三:会话间状态传递

# 会话1:完成分析,保存结果
claude -p "分析迁移影响范围,将结果保存到 refactor-plan.md" \
  --allowedTools "Read,Grep,Glob,Write"

# 会话2:读取分析结果,开始执行
claude -p "读取 refactor-plan.md,按照Phase 1的计划执行迁移" \
  --allowedTools "Read,Grep,Glob,Edit,Bash"

5.5 非交互模式批量执行

对于确定性的、模式一致的迁移任务,使用 -p 模式配合脚本实现自动化:

#!/bin/bash
# batch-migrate.sh - 批量迁移脚本

MODULES=("users" "orders" "products" "inventory" "payments")

for module in "${MODULES[@]}"; do
  echo "=== 迁移模块: $module ==="

  claude -p "迁移 src/api/$module/ 目录下所有路由到Fastify格式。
  要求:
  1. 将(req, res, next)改为(request, reply)
  2. 将res.json()改为reply.send()
  3. 将res.status().json()改为reply.status().send()
  4. 将next(error)改为reply.send(error)
  5. 运行 npm test -- --grep '$module' 验证

  如果测试失败,输出失败原因并停止。" \
    --allowedTools "Read,Edit,Grep,Glob,Bash"

  if [ $? -ne 0 ]; then
    echo "❌ 模块 $module 迁移失败,停止批量执行"
    exit 1
  fi

  echo "✅ 模块 $module 迁移完成"

  # 自动提交
  git add src/api/$module/
  git commit -m "refactor: migrate $module routes from Express to Fastify"
done

echo "🎉 所有模块迁移完成"

六、实战案例——Next.js Pages Router到App Router迁移

让我们用一个完整的案例来演示上述方法论。这是一个真实的迁移场景:将Next.js 13的Pages Router迁移到App Router。

6.1 情报收集

claude -p "分析这个Next.js项目的路由结构:
1. 列出pages/目录下所有路由文件
2. 识别使用了getServerSideProps的页面
3. 识别使用了getStaticProps/getStaticPaths的页面
4. 识别使用了API Routes的端点
5. 统计每个页面使用的Next.js特有API

按迁移复杂度(简单→复杂)排序输出" \
  --allowedTools "Read,Grep,Glob"

预期输出:

## 路由迁移分析

### 简单(纯静态页面,无数据获取)
- pages/about.tsx - 纯展示页面
- pages/contact.tsx - 纯表单页面
- pages/404.tsx - 自定义404

### 中等(使用getServerSideProps)
- pages/index.tsx - 首页,获取文章列表
- pages/blog/[slug].tsx - 博客详情页
- pages/dashboard.tsx - 用户仪表盘

### 复杂(API Routes + 混合数据获取)
- pages/api/auth/[...nextauth].ts - NextAuth API
- pages/api/webhooks.ts - Webhook处理
- pages/api/graphql.ts - GraphQL端点

### 统计
- getServerSideProps: 3个页面
- getStaticProps: 1个页面
- API Routes: 3个端点
- 使用useRouter: 5个组件

6.2 生成迁移计划

> 基于上面的分析,制定App Router迁移计划。
> 
> 约束:
> - Pages Router和App Router必须能共存(Next.js支持)
> - 优先迁移简单页面验证流程
> - API Routes最后迁移(影响最大)
> - 每个页面迁移后验证功能完整性

6.3 执行迁移——以博客详情页为例

> 迁移 pages/blog/[slug].tsx 到 app/blog/[slug]/page.tsx
> 
> 当前页面使用了:
> - getServerSideProps 获取博客内容
> - remark/remark-html 渲染Markdown
> - useSession 检查登录状态
> 
> 迁移要求:
> 1. getServerSideProps → Server Component直接fetch
> 2. 保持URL结构不变:/blog/[slug]
> 3. 客户端交互部分提取为Client Component
> 4. 添加loading.tsx和error.tsx
> 5. SEO元数据使用generateMetadata

Claude Code生成的迁移代码:

// app/blog/[slug]/page.tsx
import { notFound } from 'next/navigation';
import { Metadata } from 'next';
import { BlogContent } from './blog-content';
import { getPost, getPostSlugs } from '@/lib/blog';

// SEO元数据生成
export async function generateMetadata({
  params,
}: {
  params: { slug: string };
}): Promise<Metadata> {
  const post = await getPost(params.slug);
  if (!post) return { title: 'Post Not Found' };

  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      type: 'article',
    },
  };
}

// 静态参数生成(替代getStaticPaths)
export async function generateStaticParams() {
  const slugs = await getPostSlugs();
  return slugs.map((slug) => ({ slug }));
}

// Server Component - 替代getServerSideProps
export default async function BlogPostPage({
  params,
}: {
  params: { slug: string };
}) {
  const post = await getPost(params.slug);

  if (!post) {
    notFound();
  }

  return (
    <article className="prose lg:prose-xl mx-auto">
      <h1>{post.title}</h1>
      <time dateTime={post.date}>{post.formattedDate}</time>
      {/* 客户端交互组件 */}
      <BlogContent 
        content={post.htmlContent} 
        slug={params.slug}
      />
    </article>
  );
}
// app/blog/[slug]/blog-content.tsx
'use client';

import { useState } from 'react';
import { useSession } from 'next-auth/react';
import { ShareButton } from './share-button';

export function BlogContent({ 
  content, 
  slug 
}: { 
  content: string; 
  slug: string; 
}) {
  const { data: session } = useSession();
  const [liked, setLiked] = useState(false);

  return (
    <>
      <div dangerouslySetInnerHTML={{ __html: content }} />

      {session && (
        <div className="flex gap-4 mt-8">
          <button onClick={() => setLiked(!liked)}>
            {liked ? '❤️' : '🤍'} Like
          </button>
          <ShareButton slug={slug} />
        </div>
      )}
    </>
  );
}
// app/blog/[slug]/loading.tsx
export default function BlogPostLoading() {
  return (
    <div className="animate-pulse">
      <div className="h-8 bg-gray-200 rounded w-3/4 mb-4" />
      <div className="h-4 bg-gray-200 rounded w-1/4 mb-8" />
      <div className="space-y-3">
        {Array.from({ length: 10 }).map((_, i) => (
          <div key={i} className="h-4 bg-gray-200 rounded" />
        ))}
      </div>
    </div>
  );
}

6.4 验证迁移结果

claude -p "验证 app/blog/[slug]/ 的迁移结果:
1. 对比 pages/blog/[slug].tsx 和 app/blog/[slug]/page.tsx 的功能列表
2. 确认所有原有功能都已覆盖
3. 运行 npm run build 确认无构建错误
4. 检查TypeScript类型是否正确
5. 输出功能对比清单" \
  --allowedTools "Read,Bash,Grep"

6.5 完整迁移架构图

flowchart TB
    subgraph "迁移前 - Pages Router"
        P1[pages/index.tsx<br/>getServerSideProps]
        P2[pages/blog/_slug_.tsx<br/>getStaticProps]
        P3[pages/about.tsx<br/>静态页面]
        P4[pages/api/auth/[...nextauth].ts<br/>API Route]
        P5[pages/api/webhooks.ts<br/>API Route]
    end

    subgraph "迁移后 - App Router"
        A1["app/page.tsx<br/>Server Component"]
        A2["app/blog/_slug_/page.tsx<br/>Server Component + generateStaticParams"]
        A3["app/about/page.tsx<br/>Server Component"]
        A4["app/api/auth/[...nextauth]/route.ts<br/>Route Handler"]
        A5["app/api/webhooks/route.ts<br/>Route Handler"]

        A2_L[loading.tsx]
        A2_E[error.tsx]
        A2_C[blog-content.tsx<br/>Client Component]
    end

    P1 -.->|迁移| A1
    P2 -.->|迁移| A2
    P3 -.->|迁移| A3
    P4 -.->|迁移| A4
    P5 -.->|迁移| A5

    style P1 fill:#ffcdd2
    style P2 fill:#ffcdd2
    style P3 fill:#ffcdd2
    style P4 fill:#ffcdd2
    style P5 fill:#ffcdd2
    style A1 fill:#c8e6c9
    style A2 fill:#c8e6c9
    style A3 fill:#c8e6c9
    style A4 fill:#c8e6c9
    style A5 fill:#c8e6c9

七、重构后的质量守卫

7.1 自动化回归检测

迁移完成后,建立长期的质量守卫机制:

# 创建CI检查脚本
claude -p "创建一个重构回归检测脚本 scripts/refactor-check.sh,检查:
1. 是否有文件意外导入了已移除的依赖
2. 是否有文件仍在使用旧框架API
3. TypeScript编译是否通过
4. 所有测试是否通过
5. Bundle大小是否在合理范围内(与迁移前对比)

脚本应在CI/CD中运行,任何检查失败都应返回非零退出码。" \
  --allowedTools "Read,Write,Bash"

7.2 性能基准对比

claude -p "对比迁移前后的性能基准:
1. 使用 autocannon 或 wrk 对关键API端点进行压力测试
2. 对比响应时间(P50, P95, P99)
3. 对比内存使用
4. 对比冷启动时间
5. 输出对比报告,标注性能提升/退化的端点" \
  --allowedTools "Bash"

7.3 代码质量度量

> 请对迁移后的代码进行质量评估:
> 
> 1. 计算圈复杂度变化(迁移前后对比)
> 2. 检查TypeScript strict mode合规性
> 3. 检查是否有any类型逃逸
> 4. 统计代码行数变化(新增/删除/修改)
> 5. 检查是否有死代码引入
> 6. 输出质量评估报告,每项给出A/B/C/D评级

八、常见陷阱与解决方案

8.1 上下文窗口溢出

症状 原因 解决方案
Claude Code开始"忘记"之前的修改 会话上下文超过窗口限制 按模块分多个会话,用Memory传递状态
修改不完整,遗漏文件 影响范围判断不全 先用Grep全面扫描,生成变更清单
响应质量下降 上下文噪音过多 使用 .claudeignore 排除无关文件

8.2 迁移引入的隐蔽Bug

典型案例:Express的 res.json() 会自动设置Content-Type,但Fastify的 reply.send() 在某些情况下不会。

# 让Claude Code执行针对性检查
claude -p "检查所有迁移后的路由处理器,确认:
1. 所有JSON响应都设置了正确的Content-Type
2. 所有错误响应都有统一的错误格式
3. 文件上传响应的Content-Type正确
4. 流式响应(SSE)的处理方式正确

对每个检查点输出:检查结果 ✓/✗、涉及文件、问题描述" \
  --allowedTools "Grep,Read"

8.3 测试的测试——确保安全网本身可靠

> 检查我们的测试套件是否真正覆盖了迁移中的关键变更:
> 
> 1. 统计测试覆盖率,列出覆盖率低于80%的文件
> 2. 找出迁移中修改了但没有对应测试的文件
> 3. 对高风险文件(认证、支付、订单),建议补充测试用例
> 4. 确认集成测试覆盖了所有API端点

九、完整工作流检查清单

以下是执行大规模重构时的完整检查清单:

重构前

规划阶段

执行阶段

验证阶段

收尾阶段


延伸阅读


参考来源

  1. Claude Code Documentation — Anthropic — Claude Code核心功能、Plan Mode、Memory系统的官方文档
  2. Claude Code Best Practices for Large Codebases — 上下文管理、多文件编辑、工作流优化的官方最佳实践指南
  3. Fastify Migration Guide — Express到Fastify迁移的权威参考
  4. Next.js App Router Migration — Pages Router到App Router的官方迁移路径

训练营适用性评估:

训练营类型 适用性 建议教学时长 说明
企业内训(中级开发者) ⭐⭐⭐⭐⭐ 4-6小时 有真实项目可直接演练
线上付费课程 ⭐⭐⭐⭐ 3-4小时 需提供模拟项目供练习
高校软件工程课程 ⭐⭐⭐ 2-3小时 作为软件重构章节的实践内容
开发者大会工作坊 ⭐⭐⭐⭐ 2小时精简版 聚焦方法论和一个案例演示

前置知识要求:Claude Code基础使用经验6个月以上、Git熟练、了解至少一种Web框架。建议先完成入门篇和Skill开发篇的学习。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入