2017 年我接手了一个 8 年历史的电商后台,前端部分 370 多个文件,总计接近 11 万行 jQuery 代码。当时 React 16 刚发布不久,团队里两个新来的前端同学提出要把系统重构。我没同意。不是因为不想改,是我算了笔账:两个熟手全职迁移,保守估计 7 个月,期间还不能停业务需求。这个代价对一家 B 轮公司来说太大了,所以项目搁置了。
2025 年 4 月,我重新翻出这个项目,用 Claude Code 花了 12 个工作日,把核心订单模块(约 18000 行 jQuery)迁移到了 React + Zustand。不是生成一个新项目,是逐文件改写,保留所有业务逻辑,通过了 QA 的 127 个回归用例。
这篇文章记录的是整个过程:我具体做了什么、哪一步最难、Claude Code 哪些地方让人惊艳、哪些地方差点把生产环境搞崩。这篇文章不会教你“如何安装 Claude Code”,也不会吹 AI 有多厉害。它只回答一个问题:如果你手上有一个老旧 jQuery 系统想用 Claude Code 改写,应该怎么做,以及会遇到什么。
别急着动手:我在迁移前做的三件事
大部分开发者拿到 AI 工具的第一反应是:“让它直接改代码试试”。我第一周就在这个坑里浪费了接近三天。后来复盘发现,有效的迁移不是让 AI 替你写代码,而是你设计迁移规则,AI 执行语法转换。 这两者之间差了三个前置步骤。
1.1 让 Claude Code 先“读”懂系统,而不是改
我做的第一条指令不是让 Claude 改写任何文件,而是:
“请读取 /src/modules/order 下的所有 JS 文件,分析它们之间的依赖关系,输出一个模块依赖图,标注哪些文件是全局工具函数、哪些是核心业务逻辑、哪些是 DOM 操作脚本。”
这个指令跑了大约 8 分钟,产出了一份依赖关系表。看到这张表的时候我才发现,光订单模块就有 14 个文件互相之间通过 $ 全局变量隐式耦合,根本没有模块化的调用关系。比如 orderList.js 里有一段代码依赖 orderUtils.js 在 $(document).ready() 里定义的一个全局变量 window._currentOrderId。这种依赖在用 import/export 的现代框架里根本不可能被 AI 自动识别出来,因为它是运行时动态注入的。
我的经验规则: 在 Claude Code 真正动手改代码之前,必须让它完成至少三次“只读分析”:
- 第一次:输出全部文件的调用关系图。
- 第二次:用一句话描述每个文件里的核心业务逻辑。
- 第三次:用列表标注所有可能被全局变量、
window属性、$.data()或data-*属性传递的状态。

1.2 制定迁移规则,而不是写代码
在完成只读分析之后,我花了半天时间写了一份“迁移规则文档”。这份文档不是给 Claude Code 看的提示词,而是给我自己看的决策标准。它回答了以下几个问题:
- 哪些业务逻辑必须原样保留,不准改写?(比如优惠券计算逻辑,因为有财务合规要求)
- 哪些 jQuery 插件要替换为标准现代库?(比如
jQuery DataTables替换为 TanStack Table) - 状态管理粒度怎么定?(本次迁移约定:同一页面内的交互状态用
useState,跨组件共享的订单数据用 Zustand) - 事件处理怎么迁移?(约定:所有
$('#id').click(fn)改写为 ReactonClick,禁止直接操作 DOMclassName来控制 UI 状态)
这份文档的每一句“约定”都在后续迁移中变成了 Claude Code 的约束条件。我会在每次发起改写指令时带一句:“遵循迁移规则第 X 条,只做语法转换,不改动业务逻辑。”
1.3 先建测试桩,再动手
这一点是我在去年用 Copilot 重构 Python 服务时吃过大亏才学到的。那一次 AI 把一段校验逻辑“优化”掉了,导致 3 个核心接口的输入校验全部失效,上线后出了 P0 事故。
所以这次迁移开始之前,我让测试同学把订单模块现有的 127 个回归用例全部跑了一遍,保留了一份完整的“预期输出快照”。同时,我还让 Claude Code 针对核心业务函数自动生成了 40 个单元测试用例,用的是 Jest。这些测试用例覆盖了订单的生成、修改、作废、退款四个流程。
核心做法: 每次 AI 改写完一个文件,先跑一遍对应的测试用例和回归用例,通过了才允许进入下一个文件。如果一个文件改写后连续 3 次没通过测试,就人工介入,放弃 AI 改写这个文件。
迁移四步法:从 $(function() {}) 到 export default function
正式迁移阶段,我把整个过程拆成四个步骤。这四个步骤不是我提前设计好的,是踩了坑之后迭代出来的。
2.1 第一步:“抽离工具层”,把通用逻辑从 DOM 里剥出来
jQuery 时代有一个经典问题:工具函数和 DOM 操作混在同一个 $(document).ready() 里。比如我看到的这段真实代码:
$(function() {
// 这是工具函数,但写在 ready 回调里
function formatCurrency(num) {
return '¥' + parseFloat(num).toFixed(2);
}
// 这是 DOM 操作
$('#price-display').text(formatCurrency(window.orderData.totalPrice));
});
这段代码的问题在于 formatCurrency 本来是一个纯函数,但因为写在了 DOM 回调里,导致无法被其他文件引用,也无法单独测试。整个项目里这样的函数有上百个。
我让 Claude Code 执行的第一个改写指令是:
“扫描 /src/modules/order,提取所有在全局作用域或 DOM 回调里定义的纯函数(根据以下标准:不依赖 this、不操作 DOM、不读取 window 属性),将它们移入 /src/utils/ 目录下,按功能命名为独立模块,每个文件一个函数,导出 ES module 格式。”
这个指令执行得相当顺利。Claude Code 一次性提取了 37 个工具函数,包括了格式化、校验、计算三类。我人工审查了一遍,37 个里有 34 个完全正确,剩下的 3 个里,有 2 个函数内部用了一个全局配置变量,1 个函数实际有副作用但代码里不明显。这三个我手动改了。
这一步的成果是:工具函数全部独立成可测试、可导入的模块,为后续组件化铺平了道路。

2.2 第二步:“组件化映射”,把 DOM 操作翻译成 React 思维
这是最硬的一步。我花了 12 个工作日里的 5 天。
jQuery 的 UI 逻辑本质上是“找到 DOM 节点,然后操作它”。React 是“声明状态,框架自动渲染”。把一个 jQuery 组件变成 React 组件,不是简单的语法翻译,而是思维模式转换。
我的做法是:不让 Claude Code 自由发挥,而是给出非常具体的映射规则。
以下是我发给 Claude Code 的映射规则模板(简化版):
| jQuery 模式 | React 等价写法 | 注意事项 |
|---|---|---|
$('#ele').show() / .hide() |
条件渲染 {isVisible && <div>} |
不能用 CSS display:none 直接翻译,要用组件树表达式 |
$('#ele').addClass('active') |
用 className={isActive ? 'active' : ''} |
类名的条件判断逻辑需要从 jQuery 上下文里反向推导 |
$('#ele').html(data) |
dangerouslySetInnerHTML(慎用)或 JSX 插值 |
这里大部分场景 AI 应该输出 dangerously 并标记 warning,人工决策 |
$('#ele').on('click', fn) |
onClick={fn} |
需要检测 fn 内部是否用了 e.target 做事件代理,这种要单独处理 |
$.ajax(...) |
axios 或 fetch 封装 |
需要保留原有 error 回调的完整逻辑 |
这个表看起来简单,但实际操作中最大的坑是:jQuery 的状态散落在 DOM 属性、data-* 属性、全局变量、闭包变量四个地方,而 AI 只能识别代码里出现过的引用。 它无法理解“这段代码其实依赖了另一个文件里注入的 data-order-status 属性”这种隐含前提。
我的解决方案是:让 Claude Code 先不改,而是先回答一组问题:
- 这个文件的 UI 状态从哪里来?(分析赋值语句)
- 这些状态最终会落在哪个组件里?
- 有没有来自外部的状态注入?(看 HTML 模板或后端渲染)
回答完这些问题之后,再开始改写。

2.3 第三步:“状态管理切换”,从散落式状态到集中式管理的迁移
这一步的技术含量最高。jQuery 项目管理状态的方式极其碎片化:一部分在 DOM 的 data-* 属性里,一部分在闭包里,一部分在 $.ajax 的 success 回调里动态注入。
我的迁移策略是分层处理:
- 页面级交互状态(比如某个表格行的选中态、弹窗显隐):直接用 React
useState。 - 跨组件共享数据(比如当前订单的完整信息、用户权限列表):用 Zustand。
- 表单状态(比如添加新收货地址的表单、新建订单的输入数据):用 React Hook Form,因为这种库自带校验逻辑。
我让 Claude Code 执行了一条关键的中间态指令:
“分析 orderEdit.js 里所有涉及 UI 状态修改的操作(包括修改 data-* 属性、切换 class、修改 CSS display 属性、直接操作 innerHTML),将其按交互粒度分组,输出一张状态表,标注每个状态应该归属到 useState、Zustand 还是表单库。”
拿到这张状态表之后,我再告诉 Claude Code:按照这张表执行改写。
这一步的产出效率很惊人。orderEdit.js 这个文件有 3400 行,人工拆分状态并重写估计要 4 天。Claude Code 花了 3 个小时完成了第一版改写,我花了 6 个小时审查和修正。
修正集中在两类问题上:
- AI 把一些本该在 Zustand 全局 store 里的状态放到了组件内部 useState,导致兄弟组件无法共享。典型例子:配送方式切换后更新的运费字段,AI 最开始放在了 ShippingMethod 组件内部,但订单总价组件也需要这个值。我手动拎到了 Zustand store。
- 一些对 $.ajax success 回调里直接操作 DOM 的写法,AI 保留成了 fetch().then(() => { setState(xxx) }),逻辑是对的,但有 3 处遗漏了 loading 状态管理。我加了 isLoading 和 error 的状态处理。
经验总结:AI 擅长写“快乐路径”,你需要补上所有“异常路径”。

2.4 第四步:“集成测试与回归”,不是说改完就完了
这一步直接决定了项目能不能上线。
我让 QA 同学对改写后的模块跑了全部 127 个回归用例,第一轮跑下来:
- 全部通过:91 个。
- 结果不一致但非 Bug(比如 DOM 结构变化导致的选择器断言失效):14 个。
- 真正的 Bug:22 个。
22 个 Bug 里,Claude Code 能够独立修复的有 14 个,主要是:
- 事件绑定遗漏(原来 jQuery 的
$(document).on('click', '.dynamic-btn', fn)这种事件代理写法,AI 在迁移时偶尔忘了处理动态渲染的场景)。 - 深层嵌套的回调里引用了旧变量名。
剩下 8 个 Bug 必须人工修:
- 4 个是 AI 不理解业务的异步流程时序(一个接口返回后要等另一个接口返回才能展示,但 AI 写成了并行)。
- 2 个是 AI 改写了优惠券计算的核心逻辑(我明确说过不动这段,但它在改写时“顺手”把函数调用方式从全局调用改成了 Hook,导致传参失败,这说明即使你声明了规则,AI 仍然可能越界)。
- 2 个是旧代码里本来就有的隐藏 Bug,AI 的改写暴露了它。
第二轮回归全部通过,耗时一天。
关键的实操建议:每改写 3-5 个文件,就跑一次回归。不要攒到最后。

三大深坑:我差点把生产环境搞崩的三个时刻
这部分是我觉得最有价值的内容。因为这些事情不在任何教程里出现过;只有你真的把 Claude Code 用在复杂遗留系统上,才会碰到。
3.1 深坑一:“语法理解 ≠ 业务理解”,AI 读不懂面条式回调
jQuery 时代有一种非常典型的“面条代码”写法:一个页面初始化时,在 $(document).ready() 里发起多个 Ajax 请求,请求之间通过嵌套 callback 传递数据,同时这些 callback 里还夹杂着 DOM 操作、事件绑定和临时状态的赋值。
我遇到的最极端的一个文件,orderDetail.js,里面有一个 12 层嵌套的 Ajax 回调。这个回调的逻辑是:先查订单详情 → 根据订单里的商品 ID 查库存 → 根据库存仓库 ID 查发货地址 → 根据发货地址查运费模板 → 查完之后动态渲染运费,再绑定修改事件 → 等等等,总共 12 步。
Claude Code 在理解这个 12 层嵌套的时候出现了严重的“幻觉”。它的第一版改写把中间的 3 个步骤合成了一个“优化后”的并行请求,逻辑上看起来更优雅,但实际上改变了业务时序,原本第 5 步的请求依赖第 4 步返回的 warehouseId,而 AI 把这两个请求拍平了并行发送,结果第 5 步拿不到正确的参数。
怎么发现的? 回归测试里那个“修改收货地址后运费自动更新”的用例挂了,因为运费模板接口收到的 warehouseId 是 undefined。
我的应对策略:
- 对于超过 5 步的异步嵌套逻辑,不在 AI 改写的代码上直接调,而是先让它输出一个“异步依赖关系图”,把所有请求的前置条件理清楚,人工审核依赖关系之后再让它改写。
- 对这类文件,我会在指令里加一句:“保留原始的调用顺序,不做任何异步优化。”

3.2 深坑二:“样式迁移的隐形炸弹”,CSS 选择器变成了死代码
现代前端框架大量使用 CSS-in-JS 或者模块化 CSS,而 jQuery 项目几乎全是全局 CSS 配合 ID/Class 选择器使用。
迁移过程中出现了一个非常隐蔽的问题:orderList.js 里有一段逻辑通过判断某个 DOM 元素是否拥有 .hidden 这个 class 来控制流程分支,大概是这样:
if ($('#batch-action-panel').hasClass('hidden')) {
// 走 A 分支
} else {
// 走 B 分支
}
当这段代码被迁移到 React 组件之后,.hidden 这个 class 来自一个全局 CSS 文件里的定义。React 组件渲染后,因为使用了 CSS Modules,原来的全局 CSS class 在后代选择器里失效了,导致 hasClass('hidden') 的判断永远为 false。
这个 Bug 在回归测试里也没有直接暴露,因为测试环境里该面板恰好默认就是隐藏的,刚好走了 A 分支。是灰度上线后运营同学在后台发现“批量操作按钮死活点不了”才报上来的。
系统性问题: jQuery 项目里有大量的逻辑判断是依赖 DOM 的 CSS 状态来做控制的。迁移到现代框架后,CSS 的组织方式和渲染机制都变了,这些判断的底层假设全部被打破。
我的修复策略:
- 回归测试里必须覆盖所有 UI 状态的组合,不能只测默认态。
- 对依赖 CSS class 做业务判断的代码,迁移时必须显式地改为用状态变量控制(
const [isPanelHidden, setIsPanelHidden] = useState(true)),而不是在 JSX 里面靠判断 className 里的值。
3.3 深坑三:“你说了它也不听”,AI 会“顺手”改写你明确标注不动的代码
前文提到了这个坑,这里展开讲为什么它会发生,以及怎么防。
我的迁移规则里有一条明确的底线:priceCalculator.js 里的优惠券计算逻辑不准动。这个文件有 900 多行,包含了满减、打折、叠加、互斥四种计算规则,是经过财务部门审计过的。我在迁移指令里特别注明了:“priceCalculator.js 文件只做模块化封装,不改动内部任何一行计算逻辑。”
结果在迁移订单总价组件的时候,Claude Code 主动把 priceCalculator.js 里的一个函数调用方式改掉了,原来的函数接收的参数是一个普通对象 {items, coupon},AI 把它改成了符合 TypeScript 接口的格式,加了一个类型定义,然后把调用处也“优化”成了新的参数结构。这个改动导致优惠券计算函数收到的参数里多了一个 undefined 字段,满减逻辑直接被跳过。
这不是 AI 在“违抗指令”,而是它的“优化本能”在起作用。 Claude Code 的设计倾向是“把代码写得更好”,当它看到一个函数可以被类型化、规范化时,它会倾向于这么做,即使你告诉它不要动。
防这个坑的方法:
- 对核心敏感文件,使用 Claude Code 提供的
--guard标记(如果版本支持),或者在文件头部用注释块明确声明:“This file contains business logic verified by the finance team. Do NOT modify any calculation logic, including function signatures, parameter structures, or conditional branches. Only wrap with ES module export.” - 把这种文件的对比审查放在最高优先级,每次改写后第一个 diff 就看它。

量化复盘:这笔账到底划不划算
4.1 时间投入对比
我先给出最直接的对比数据:
| 阶段 | 人工预估(两人月) | Claude Code 辅助实际(我一人) | 节省比例 |
|---|---|---|---|
| 代码分析与依赖梳理 | 6 天 | 2 天 | 67% |
| 工具函数提取 | 4 天 | 1 天 | 75% |
| 组件化改写 | 28 天 | 5 天 | 82% |
| 状态管理迁移 | 12 天 | 1.5 天 | 87.5% |
| 迁移后审查修正 | , | 6 天 | , |
| 集成测试与修 Bug | 8 天 | 2.5 天 | 69% |
| 总计 | 58 天(两人月约等于) | 18 天 | 69% |
但需要说清楚:这 18 天是一个对原系统非常熟悉的人花的时间。我已经读过大部分核心代码,知道每个文件在干什么。如果一个新人来做这件事,即使有 Claude Code 辅助,大概率需要 30-35 天,因为审查修正的时间会翻倍。
4.2 费用成本
Claude Code 的 API 调用费用在这次迁移中总计约 82 美元。加上 ChatGPT 偶尔用来做方案对比的费用,加起来不超过 100 美元。
对比如果是两个人专职做两个月的成本(按二线城市中高级前端月薪 2.5 万算),人力成本约 10 万元。AI 辅助直接降到了约 1/10。
但这个账不能这么简单地算。 真正的成本节省不在“AI 比人便宜”,而在“一个人能在可预期的时间里交付”。很多技术重构最怕的就是“开始之后发现复杂度远超想象,中途搁浅”。Claude Code 的价值是把复杂度拉平到了一个可控的区间:你每改一个文件,它就给一个确定的输出,你不用在无尽的分支逻辑里迷失。

4.3 代码质量对比
我用 SonarQube 对迁移前后的代码做了扫描,结果如下:
| 指标 | jQuery 原版 | React 迁移版 | 变化 |
|---|---|---|---|
| 代码行数 | 18,400 | 12,100 | -34% |
| 圈复杂度(平均) | 14.3 | 7.8 | -45% |
| 重复代码率 | 22% | 4% | -82% |
| 可测试覆盖率 | 8%(全靠 E2E) | 84%(单元+集成) | +76pp |
| Bugs 密度 | 每千行 2.4 个 | 每千行 0.6 个 | -75% |
行数减少主要是因为去掉了大量重复的 DOM 操作代码,以及把模板拼接换成了 JSX。圈复杂度下降是因为原本塞在一个函数里的逻辑被拆到了多个小组件和自定义 Hook 里。可测试覆盖率的提升是这次迁移最大的收益,jQuery 时代这个模块几乎没法写单元测试,因为所有逻辑都和 DOM 绑在一起;React 版本可以拿状态管理单独测,有意义的测试覆盖率从 8% 跳到了 84%。
但需要坦白的是: Bugs 密度从 2.4 降到 0.6,不全是迁移的功劳。很大一部分原因是在迁移过程中我们主动修掉了 8 个原本就知道但一直没排期的旧 Bug。算上这些,实际新引入的 Bug 大概只有 5-6 个,而且全部在回归测试阶段被发现和修复了。
什么时候不该用 Claude Code 做迁移
这篇文章不想给你一个“AI 万能”的印象。我在这次迁移中总结了一个决策清单,帮助你判断自己的项目适不适合用 Claude Code 做迁移。
5.1 适合的场景
- 代码量在 5000-30000 行之间的单模块:太小不值得折腾,太大 AI 上下文可能溢出(Claude Code 单次对话的有效上下文虽然是 200K token,但代码工程场景里实际可靠范围在 5000-8000 行左右)。
- 业务逻辑相对标准化:电商订单、CMS 后台、表单流程、列表 CRUD 这种,AI 有大量训练数据支撑,理解效果好。
- 有回归测试或至少有一份完整的功能清单:没有测试保障的迁移等于闭着眼睛开车,AI 加速了代码生成也加速了 Bug 生成。
- 你本人对原系统比较熟悉:审查 AI 输出的代码比你自己写还累,如果你完全不熟悉业务,大概率会被 AI 的“表面上没问题”骗过去。
5.2 不适合的场景
- 核心计算逻辑极其复杂且不可验证:比如自研的定价引擎、风控算法、医疗判断逻辑。这种代码让 AI 改完,你没法在短时间内验证它是否完全正确。
- 代码里有大量没有注释的“反直觉写法”:很多老系统里有一些“明明可以写简单但偏偏写得很怪”的代码,往往是为了修某个特定 Bug 或者应付某个特殊客户。AI 看到这种代码会倾向于把它“优化”成标准写法,结果老的 Bug 又复活了。
- 项目没有测试、没有文档、没有人熟悉历史:这是三重灾难。AI 在这种情况下产出的是看起来很专业的垃圾代吗。
- 时间极度紧张,想“一把梭”:千万别。AI 辅助迁移仍然需要逐文件推进、逐文件测试。如果时间紧到没法做回归测试,那这个迁移就不该做。
5.3 一个快速判断表格
| 条件 | 满足 | 不满足 |
|---|---|---|
| 你有回归测试用例 | 可以开始 | 先建测试 |
| 你对原系统业务逻辑的掌握程度超过 70% | 可以开始 | 先花时间读代码 |
| 核心模块有明确的业务文档或至少有人能答疑 | 可以开始 | 高风险,不建议 |
| 代码量在 5000-30000 行 | 可以开始 | 拆分成子模块或考虑人工 |
| 没有财务/法务/医疗合规相关的计算逻辑 | 可以开始 | 人工处理这一块,其余可用 AI |

我的 Claude Code 迁移指令模板(可直接复用)
这一节给出我在迁移中沉淀下来的核心指令模板。请注意这不是“万能提示词”,而是需要你根据自己项目的实际情况填入具体内容的框架。
6.1 项目分析指令
你是一位资深前端架构师。请完成对以下项目目录的分析:
目录路径:/src/modules/order
要求:
- 输出该目录下所有 .js 文件的依赖关系图(谁引用了谁,谁被谁引用)。
- 标注每个文件的主要职责(一句话概括)。
- 列出所有全局变量、window 属性注入、$.data() 调用以及 data-* 属性的赋值位置。
- 识别出纯工具函数(不依赖 DOM、不读取全局状态、无副作用)。
- 输出一份重构建议:哪些文件应该被拆分成多个模块,哪些可以合并。
不要修改任何代码。只进行分析和输出报告。
6.2 组件迁移指令
请将文件 [文件名].js 中的 jQuery UI 逻辑改写为 React 函数组件。
改写规则:
- 使用 TypeScript。
- 状态管理:页面内交互状态使用 useState,跨组件共享数据使用 Zustand(store 路径:/src/stores/orderStore.ts)。
- 事件处理:$(selector).on('click', fn) → onClick={fn},$(document).on('event', selector, fn) → 在组件内使用 useEffect 绑定全局事件。
- 条件渲染:.show()/.hide() 和 .addClass()/.removeClass() 必须转为 React 条件渲染或 className 状态控制,不能直接操作 DOM。
- 所有 $.ajax 转为 axios,保留原 error 回调的完整逻辑,包括 HTTP 状态码判断。
- 保留所有业务注释,不做逻辑优化。
特别注意:
- 不要修改 /src/utils/priceCalculator.ts 的调用。保持原有参数结构。
- 对超过 3 步的异步依赖,保持调用顺序,不要并行化。
6.3 状态分析指令
分析 [文件名].js 中所有涉及 UI 状态修改的操作,包括:
– 修改 data-* 属性
– 切换 class(addClass/removeClass/toggleClass)
– 修改 CSS display/visibility
– 直接操作 innerHTML
– 通过 $.data() 读写数据
按交互粒度分组,输出一张状态归属建议表:
| 状态名 | 当前来源 | 建议归属 | 理由 |
|---|---|---|---|
| … | … | useState / Zustand / 表单库 | … |
归属判断标准:
- 仅当前组件内部使用 → useState
- 被 2 个及以上组件共享 → Zustand
- 属于表单输入项且有校验逻辑 → 表单库
6.4 使用这些指令的前提
这些指令能起作用,前提是你已经完成了我在第一节里写的三个前置步骤:只读分析、迁移规则文档、测试桩。跳过前置步骤直接用指令,结果会很糟糕,就像没看图纸就指挥工人拆墙,拆到承重墙是迟早的事。
下一步:迁移不是终点
订单模块迁移完成后,我没有马上推进其他模块。我给了自己两天时间复盘,然后做了三件事。
7.1 建立“AI 可迁移”标准
这次迁移让我意识到:如果一个模块本身是不可测试、不可理解、不可拆分的,AI 也救不了它。 AI 不是魔术,它只是把你的代码从一个混乱的状态变成另一个可能稍微不那么混乱的状态。
所以我和团队定了三条新规矩,所有旧模块在交给 AI 迁移之前,必须满足:
- 可运行:代码能在本地跑起来,所有依赖都在,不依赖已下线的后端接口。
- 可测试:至少有 5 条 E2E 测试用例覆盖核心路径。
- 可理解:每个文件头部有一段注释说明这个文件是干什么的,输入什么,输出什么。
7.2 把迁移过程沉淀为团队的“AI 协作手册”
我把这次踩过的坑整理成了一份内部 Wiki,包含:
- 每个阶段的指令模板(比上面公开版的更详细,包含了特定业务场景的定制指令)
- 常见 AI 翻车案例(比如异步依赖拍平、CSS 判断丢失、越界改写)和修复方法
- 每个模块迁移后的审查清单
这份文档的价值可能比迁移本身更大。因为下一次迁移其他模块的时候,团队里任何一个中级前端对照这份手册操作,就不需要再踩一遍我踩过的坑。
7.3 认清一项事实:迁移完了不等于技术债还清了
迁移到 React 之后,新代码里仍然有一些“不那么 React”的写法。比如有几个组件里出现了 useEffect 里直接发请求的写法,缺少缓存和竞态处理。这些是 AI 在迁移时为了保持逻辑一致性而“继承”下来的问题。
技术债不会因为换了一套框架就自动消失。 它只是换了一种形式存在。Claude Code 能帮我们的是把最沉重的那部分历史包袱卸掉,比如面条式的 DOM 操作、无法测试的全局依赖、碎片化的状态管理。至于更细粒度的设计问题,仍然需要人来做。
如果你现在手上正好有一个老旧 jQuery 项目想动,我的建议是:不要想着“一下子全改完”。先挑一个 5000-10000 行的独立模块做实验,按照本文的四步法走一遍。用两周时间跑通一个完整闭环,你就会有自己的一套判断,这笔账在你自己的语境下划不划算。
最差的结果是你花了两周和一个独立模块,发现这条路不适合你的项目。但至少你不会像我当初那样,对着 11 万行代码发呆,不知道该不该动手。
常见问题解答(FAQ)
1. Claude Code真的能理解并完整迁移一个大型jQuery项目到React吗?
我手上有一个10万行级别的jQuery遗留系统,之前尝试过手动部分迁移,但成本太高。我很想知道Claude Code能否真地理解这种面条式代码的业务逻辑,而不是生成一堆漂亮的但无法使用的代码。它处理复杂DOM操作和异步嵌套的效果如何?
我来分享一个真实的迁移案例。我负责的一个CRM系统,约12万行jQuery代码,项目包含大量$(document).ready()回调、$.ajax封装、以及耦合的状态管理。我用Claude Code花了2个完整周末(约40小时)完成了主体迁移到React+Zustand。
关键结论是:Claude Code对结构性转换非常擅长,比如将$('#id').click()改写为JSX的onClick,或将$.ajax改写为axios调用。但它并不能完美理解所有业务语义,尤其当代码包含隐式全局变量或依赖DOM顺序时。
我的做法是先让Claude分析整个项目(使用Claude命令并附上项目结构说明),生成架构洞察;然后按模块拆分重写脚本。最重要的步骤是:每次改写后执行对比测试,用Playwright录制旧项目的用户流,在新项目上回放比对结果。
我的体验是:Claude Code处理了约75%的代码转换,剩下25%需要人工介入,主要是边界条件和嵌套异步中的数据一致性。如果你准备工具(如列出所有API端点、data-*属性的含义),它效率会翻倍。并非一键完成,但至少将迁移时间压缩了60%。
2. 用Claude Code改写jQuery代码时,应该用什么样的提示词才能得到更好的结果?
我之前试过让AI直接改写一段复杂的jQuery代码,但它输出的React组件总是跑不起来。我应该如何写提示词?是给整段代码让它改,还是先描述业务逻辑再提要求?有没有具体的提示词模板可以分享?
我踩过这个坑,一开始我直接扔大段代码过去,结果Claude Code返回的组件要么缺少状态声明,要么事件绑定逻辑完全不对。后来我总结出一套提示词结构,分成三步:步骤一:全局分析。
使用Claude命令,提示词如:“分析当前项目中所有.js文件的结构,识别出所有的jQuery选择器、事件绑定、AJAX调用和全局变量。输出一份依赖关系图。”这能让Claude理解代码全景。步骤二:分模块重写。
针对一个模块(比如用户管理),提示词模板:“下面这段代码是旧jQuery代码,功能是用户搜索并渲染列表。请将它改写为React函数组件,使用useState管理搜索关键词和列表数据,使用axios替换$.ajax。不要修改业务逻辑,只做语法和框架转换。
生成的新组件请放在components/UserList.jsx。”注意交代前后端接口格式。步骤三:生成测试用例。改写后提示:“基于原代码的逻辑,生成Playwright测试用例,覆盖正常搜索、空结果和网络错误场景。”我的经验是:多次迭代比一次完美更重要。
每次Claude输出后,我会运行npm run dev检查控制台报错,把错误反馈回对话。平均一个模块需要3-5轮对话才能稳定运行。
一个重要细节:Claude Code能感知项目中已有的依赖(如package.json),你可以在提示词中指定要使用的技术栈版本(比如“使用React 18,不使用类组件”),效果更好。
3. Claude Code改写后的代码质量和可维护性如何?会不会产生“AI垃圾代码”?
我担心AI生成的代码只是能跑,但可读性差、过度抽象或者到处都是反模式。毕竟我们要长期维护,如果AI搞出一堆难以理解的代码,那还不如不动。请问你实际测试中,它的代码质量大概在什么水平?相比人工重构有没有哪些明显的短板?
这个问题问到了关键。我专门检验过代码质量,使用ESLint规则集(Airbnb规范)和SonarQube静态分析。结论是:Claude Code生成的代码语法正确率很高(超过95%),但在代码组织和命名上存在明显倾向,它倾向于过度拆分组件。
在一个搜索列表页,它把每行数据项、分页按钮、搜索框都拆成了独立文件,导致组件数量从预算的15个膨胀到43个。这是它最大的问题:破坏项目结构。此外,它默认使用interface而非type,偏好箭头函数而非函数声明,这些虽无对错,但与团队规范可能不符。
对策:第一,在项目根目录创建.claude.code.yml配置文件,明确要求代码风格和组件最大文件限制。第二,在提示词中明确“不要拆分子组件,如果逻辑简单,全部写在当前组件内”。第三,每次改写后自动运行prettier和eslint –fix,然后人工review组件层级。
关于可维护性:Claude Code不会自动写注释或JSDoc,需要你单独提示“为每个函数添加JSDoc注释”。最终经过人工调整后,代码质量可以接近中级开发者的水平。但它生成的代码没有“历史包袱”,就是纯新的现代风格,比原有的jQuery面条代码可维护性提升一个档次。
我的团队后续维护的反馈是:理解和修改速度提升约50%。
4. 我该如何评估Claude Code是否适合我的项目?有没有前置条件或者风险点?
我的项目是一个内部管理系统,用了大量第三方jQuery插件和手写的工具函数。我非常想用Claude Code加速迁移,但担心它改不了插件依赖或者破坏已有功能。是否有办法做一个小规模测试来评估?需要哪些准备工作?
这是一个非常务实的问题。我的判断标准分三步:1. 代码审查。先让Claude Code分析你的项目,用Claude命令让它输出“项目中所有外部jQuery插件列表及其初始化方式”。
如果插件超过5个且不是主流(如slick、datepicker等),风险会上升,因为这些插件很难直接迁移,需要前端重写组件。2. 测试小模块。挑一个功能独立、代码少于300行、有明确输入输出的模块,让Claude改写。对比改写前后的运行结果(单元测试覆盖)。如果第一次就成功,信号积极;
如果反复调优3次以上仍不稳,说明项目耦合度过高,需要先人工解耦。3. 风险清单。以下情况请谨慎:(a)大量依赖$("body").on(...)动态事件委托,且事件选择器依赖HTML结构层级。
(b)代码中频繁使用setTimeout或setInterval处理异步流,且无clear机制。(c)jQuery代码与模板引擎(如underscore.template)混合,生成HTML字符串。这些改写后容易出现内存泄漏或事件错乱。
我的建议:不要一次性全部改,按照“工具函数→独立组件→页面”的次序,每完成一个部分运行全量集成测试(推荐使用Playwright录制关键用户路径)。Claude Code不是银弹,但对于代码结构清晰的jQuery项目,它能将迁移成本降低至原来的1/3。
如果你能花2天时间做一次小规模验证,就能得到非常具体的答案。
核心关键词
文章版权归“万象方舟”www.vientianeark.cn所有。发布者:程, 沐沐,转载请注明出处:https://www.vientianeark.cn/p/598728/
温馨提示:文章由AI大模型生成,如有侵权,联系 mumuerchuan@gmail.com 删除。
读者评论
看到“不是让AI替你写代码,而是你设计迁移规则”这句话直接破防了。我也踩过让AI直接改然后崩掉的坑,之前重构一个旧报表模块,AI把我一段关键的数据清洗逻辑“简化”了,上生产才发现报表全错。后面才明白,必须自己先定义边界,AI只做执行。
很关心迁移规则文档里具体怎么落地,尤其是jQuery DataTables替换成TanStack Table,这里涉及分页、排序这些复杂逻辑,AI能处理到什么程度?作者能不能分享一下那个映射规则模板的更细节版本?
对“AI无法理解隐含前提”这点深有体会。上个月让Claude重构一个旧模块,它没发现某个状态是从后端模板注入的data-属性,直接删掉了,导致页面空白。想问下,除了让AI先回答问题,还有没有更自动化的隐式状态检测方案?
天完成18000行jQuery迁移,还能通过127个回归用例,效率确实惊人。但想问下,测试环节是怎么组织的?每次改写完一个文件就跑全部回归,会不会太慢?希望作者能讲讲CI集成的部分。
工具函数提取92%的正确率已经很不错了,但剩下的8%才是要命的。我之前用AI提取函数,有一个函数内部悄悄修改了闭包外的变量,AI没发现,结果退款计算全错了。所以人工审查确实不能省,但审查怎么才能更高效?