这篇是 Vue2→Vue3 迁移系列的实操篇(下),聚焦选项式路线和收尾工作。 上篇讲了 组合式路线的完整流程,这篇则是"能不能用更低成本跑通"的尝试。
组合式路线走完一遍之后,我开始想一个问题:如果只是"先让 Vue3 跑起来",能不能更快?
选项式路线的核心思路是——用 AST 工具做 80% 的规则转换,只让 AI 处理剩下那些工具搞不定的边界场景。
选项式路线的工具链
gogocode:基于 AST 的转换
gogocode 是阿里出的一个基于 AST 的代码转换工具,自带 Vue2→Vue3 和 element-ui→element-plus 的转换插件。
# 安装
npm install gogocode-cli -g
# 第一步:Vue2 → Vue3 基本语法转换
gogocode -s ./src -t gogocode-plugin-vue -o ./src-out
# 第二步:element-ui → element-plus 转换
gogocode -s ./src-out -t gogocode-plugin-element -o ./src-out-element
# 用转换结果覆盖 src
cp -r ./src-out-element/* ./src/这两步能覆盖大部分机械性转换:this.$emit → context.emit、value/input 事件改名、Vue.filter 废弃提示等。
gogocode 搞不定的
用了之后发现,gogocode 的问题清单比预期长:
| 问题 | 影响范围 | 能否修复 |
|---|---|---|
return (<></>) JSX 语法不转换 | render 函数 | 需要 AI |
| element-plus 的样式和国际化路径不修正 | 全局样式引用 | 可手动批量 |
| icon 转换时属性会被吞掉 | 使用 icon 的组件 | 需要人工 |
v-model 转换不完整 | 部分双向绑定 | 需要人工 |
el-drawer 的 :visible 未转为 :model-value | 对话框类组件 | 可手动批量 |
filters 转换不完整(换行导致规则未命中) | 模板中的过滤器 | 需要 AI |
mapState 引入偶尔遗漏 | vuex 相关文件 | 需要人工 |
| `Number | String` 类型声明变非法 | props 定义 |
总结:gogocode 大约能处理 60-70% 的转换,剩下的就是 AI 和人工的战场。
选项式的 Prompt:比组合式简单很多
因为 gogocode 已经处理了大部分语法转换,留给 AI 的 Prompt 可以精简很多:
# 任务
对上面的代码进行如下处理
## vue 版本重构
- 重构为非 TypeScript 的 Vue3 代码
- 必须使用 Vue3 的选项式风格,不允许使用组合式
### render → template
- 如果代码在选项中使用了 render 方式渲染,改为 template 风格
- 如果遇到类似 JSX 的 return (<></>) 语法,改为 h 函数渲染
### message 组件
- element-plus 中 message 改为 import { ElMessage } from 'element-plus'
## 约束
- 多级引用使用 ?. 可选链
- 即使不需要修改也返回原代码
- 只返回代码文本,不返回 markdown 格式
对比一下:
| 维度 | 组合式 Prompt | 选项式 Prompt |
|---|---|---|
| 长度 | ~50 行 | ~20 行 |
| 涉及的技能数 | 8 个 | 3 个 |
| 需要知识库 | 是(hooks 代码) | 否 |
| 处理 this | 全面重写 | 不用管 |
| 处理 mixin | 先转再喂 | 不用管 |
选项式路线的 Prompt 几乎不需要处理 this,因为选项式 API 里 this 仍然是有效的上下文引用。也不需要先转 mixin 再当知识库——mixin 在选项式里照常工作。
执行流程对比
选项式路线步骤更少、Prompt 更简单、不需要 mixin 预处理这个前置环节。代价是你得接受代码最终是选项式风格——如果团队已经决定全面拥抱组合式,那这条路就不适合。
通过特征识别需要 AI 处理的文件
gogocode 跑完之后,不是所有文件都需要 AI 再过一遍。理想情况下,应该能通过文件特征自动识别"哪些文件还需要 AI 处理"。
目前能识别的特征:
- 包含
return (<></>)的 render 函数 - 包含
filters转换不完整的场景 - 包含
Vue.use的非入口文件
但说实话,这个特征库还不够完善。实际操作中,更多是在调试过程中发现问题,记录文件路径,再批量交给 AI。
收尾:无论哪条路线都要做的事
构建系统改造
无论选哪条路线,你最终都需要有人把项目的构建流程跑通。从 webpack 切到 vite、调整入口文件、配置代理、处理环境变量——这些 AI 帮不了太多,需要对项目构建有理解的人来处理。
Mock 和接口代理
不要期望转完就能跑。准备好 Mock 文件或者配置接口代理,缩小调试范围:
- 缩减 router,只保留你要调试的页面
- 移除不相关的第三方 SDK 调用
- 用代理工具把接口请求转发到可用的环境
样式问题
无论组合式还是选项式,这两条路线都不处理样式。
理论上可以让 AI 基于社区信息做兼容,但实际操作中,样式问题的范围太大、项目间差异太大,AI 容易改出新问题。建议从组件库的更新日志入手,定点修复。
两条路线的实际感受
| 组合式路线 | 选项式路线 | |
|---|---|---|
| AI 参与深度 | 深,全流程依赖 | 浅,只处理边界 |
| Prompt 工程量 | 大,3 套 prompt + 知识库 | 小,1 套简单 prompt |
| 转换质量 | 质量波动大,需要大量 review | 基础部分稳定,边界需 review |
| 人工调试时间 | 长,到处都可能出意外 | 短,问题集中在特定模式 |
| 最终代码风格 | 统一组合式 | 保持选项式 |
| 适合场景 | 团队决定统一组合式 | 先跑起来,后续再优化 |
如果让我重新来一次,我会建议:先用选项式路线跑通,再在后续迭代中逐步把高频模块改成组合式。原因很简单——先跑起来比一步到位更务实。
还没解决的问题
写到最后,诚实地列一下目前还悬着的:
- 大文件截断——输出 token 上限导致超长文件转换不完整,目前只能手动拆
- 变量名冲突——组合式路线中
ref解构后的同名变量,AI 偶尔会生成有歧义的代码 - 装饰器——没有处理,如果项目用了 TypeScript 装饰器,这是个坑
- 端到端验证——目前还没有自动化的验证手段,只能人工对比页面效果
- 样式一致性——如上所述,没有好方案
这些问题都不是不可解,只是在当前阶段没有足够的时间去填。如果你的项目遇到了类似的困境,希望这份笔记能帮你少走一些弯路。
系列导航:
- 方案推演:Vue2→Vue3 路线选择 — 要不要迁?选哪条路?
- 实操(上):组合式路线 — Prompt 工程与完整流程
- 实操(下):选项式路线与现实收尾 — 你正在读的这篇