如何写一个babel插件
如何写一个babel插件
Babel 解析成 AST,然后插件更改 AST,最后由 Babel 输出代码
那么 Babel 的插件模块需要你暴露一个 function,function 内返回 visitor
module.export = function(babel){ return { visitor:{ } } }
visitor 是对各类型的 AST 节点做处理的地方,那么我们怎么知道 Babel 生成了的 AST 有哪些节点呢?
这里我们看到 const result = 1 + 2 中的 1 + 1 是一个 BinaryExpression 节点,那么在 visitor 中,我们就处理这个节点。
var babel = require('babel-core'); var t = require('babel-types'); const visitor = { BinaryExpression(path) { const node = path.node; let result; // 判断表达式两边,是否都是数字 if (t.isNumericLiteral(node.left) && t.isNumericLiteral(node.right)) { // 根据不同的操作符作运算 switch (node.operator) { case "+": result = node.left.value + node.right.value; break case "-": result = node.left.value - node.right.value; break; case "*": result = node.left.value * node.right.value; break; case "/": result = node.left.value / node.right.value; break; case "**": let i = node.right.value; while (--i) { result = result || node.left.value; result = result * node.left.value; } break; default: } } // 如果上面的运算有结果的话 if (result !== undefined) { // 把表达式节点替换成number 字面量 path.replaceWith(t.numericLiteral(result)); } } }; module.exports = function (babel) { return { visitor }; }
插件写好了,运行下插件试试
const babel = require("babel-core"); const result = babel.transform("const result = 1 + 2;", { plugins:[ require("./index") ] }); console.log(result.code); // const result = 3;
与预期一致,那么转换const result = 1 + 2 + 3 + 4 + 5;呢?
结果是: const result = 3 + 3 + 4 + 5;
这就奇怪了,为什么只计算了1 + 2 之后,就没有继续往下运算了?
我们看一下这个表达式的AST 树
你会发现Babel 解析成表达式里面再嵌套表达式。
表达式( 表达式( 表达式( 表达式(1 + 2) + 3) + 4) + 5)
而我们的判断条件并不符合所有的,只符合1 + 2
// 判断表达式两边,是否都是数字 if (t.isNumericLiteral(node.left) && t.isNumericLiteral(node.right)) {}
那么我们得改一改
第一次计算1 + 2 之后,我们会得到这样的表达式
表达式( 表达式( 表达式(3 + 3) + 4) + 5)
其中3 + 3 又符合了我们的条件, 我们通过向上递归的方式遍历父级节点
又转换成这样:
表达式( 表达式(6 + 4) + 5)
表达式(10 + 5)
15
// 如果上面的运算有结果的话 if (result !== undefined) { // 把表达式节点替换成number 字面量 path.replaceWith(t.numericLiteral(result)); let parentPath = path.parentPath; // 向上遍历父级节点 parentPath && visitor.BinaryExpression.call(this, parentPath); }
到这里,我们就得出了结果const result = 15;
那么其他运算呢:
const result = 100 + 10 - 50>>>const result = 60;
const result = (100 / 2) + 50>>>const result = 100;
const result = (((100 / 2) + 50 * 2) / 50) ** 2>>>const result = 9;
前端工程化