CodeMod
(Code Modification) 的应用场景非常多,我在过去几年就使用 ‘codemod‘ 升级过多个项目,节省了大量的人力成本:
- 将原生微信小程序转换到 Taro; 后面又从 Taro 2 升级到 Taro 3
- Sonar / Eslint 问题修复。
- 前端多语言自动提取
- …
除此之外,codemod 也可以用在以下场景:
- 框架升级,比如 Next.js 升级、Vue 3 升级
- 语言升级,将废弃的旧语法替换从新语法
- 代码格式化
- API 重构
- 代码检查等等
如果你有这方面的需求,那这篇文章很适合你。
前置知识:你需要对编译原理有基本了解,如果你感到吃力,可以看看我之前写的文章:深入浅出 Babel 上篇:架构和原理 实战
编写一个代码升级/重构程序主要涉及以下环节:
这里每个环节都有很多库/方案可以选择,比如:
- 文件查找: 可以使用
Glob
通配符库来查找或忽略文件,比如 node-glob、fast-glob、globby 等 - AST parse: 这个需要根据特定的语言进行选择。比如 JavaScript 可以选择
Babel
(推荐)、Esprima
、Acorn
、swc
;CSS 可以使用postcss
、lightning css
;Vue SFC 可以使用其官方的 vue-template-parser 等等。更多方案,可以探索一下 AST Explorer,这里列举了市面上主流的 Parser - AST Transform: 将 AST 解析出来之后,可以根据自己的需求来改写 AST。不同语言/parser 处理规则会有较大的差异。AST parse 和 transform 可以选择一些工具来简化工作,比如
Jscodeshift
、gogocode
,本文接下来会深入讲解这些工具。 - Code Generate: 将 AST 转换为代码。我们要尽可能地维持原有的代码格式,否则代码 Diff 会很难看。这个阶段可以选择
recast
这类方案,它可以尽量维持代码的原有格式;另一种方案就是使用代码格式化工具,比如prettier
、eslint
,也可以最大限度维持代码的格式。 - 写入代码: 调用 fs 写入。
将这些东西串起来,你可能还需要一些库,帮你快速编写命令行工具,例如 yargs、commander、inquirer.js
接下来我将介绍 codemod 这个领域一些主流的库,这些库都各有所长,有些提供了一整套的流程,有些则提供了更高效的 AST 查找和替换方法。
Recast
recast 是一个知名的库,很多 CodeMod 工具都是基于它来实现的。我们通常将它作为 JavaScript 的 AST 转换器
和非破坏(nondestructive)代码格式化
工具来使用。
简单说就是使用 recast 进行’代码生成‘可以最大程度地保持代码原本的格式。