如何写一个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;

前端工程化 文章被收录于专栏

前端工程化

全部评论

相关推荐

11-04 14:10
东南大学 Java
_可乐多加冰_:去市公司包卖卡的
点赞 评论 收藏
分享
11-07 13:31
怀化学院 Java
勇敢牛牛不怕难:又疯一个
点赞 评论 收藏
分享
评论
1
收藏
分享
牛客网
牛客企业服务