学习完了 babel 的编译流程、AST、api 之后,我们已经可以做一些有趣的事情了。
# 需求描述
我们先做一个简单的功能练练手:
我们经常会打印一些日志来辅助调试,但是有的时候会不知道日志是在哪个地方打印的。希望通过 babel 能够自动在 console.log 等 api 中插入文件名和行列号的参数,方便定位到代码。
# 实现思路分析
需要做的是在遍历 AST 的时候对 console.log、console.info 等 api 自动插入一些参数,也就是要通过 visitor 指定对函数调用表达式 CallExpression(这个可以通过 astexplorer.net 来查看) 做一些处理。CallExrpession 节点有两个属性,callee 和 arguments,分别对应调用的函数名和参数, 所以我们要判断当 callee 是 console.xx 时,在 arguments 的数组中中插入一个 AST 节点。

# 代码实现
首先把 parse、transform、generate 的框架搭好:
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const sourceCode = `console.log(1);`;
const ast = parser.parse(sourceCode, {
sourceType: 'unambiguous'
});
traverse(ast, {
CallExpression(path, state) {
}
});
const { code, map } = generate(ast);
console.log(code);
@前端进阶之旅: 代码已经复制到剪贴板
(因为 @babel/parser 等包都是通过 es module 导出的,所以通过 commonjs 的方式引入有的时候要取 default 属性。)
parser 需要指定代码是不是包含 import、export 等,需要设置 moduleType 为 module 或者 script,我们干脆设置为 unambiguous,让它根据内容是否包含 import、export 来自动设置 moduleType。
搭好框架之后,我们先设计一下要转换的代码:
