进入es6时代,大家都知道有很多浏览器是不支持es6代码的,但是为啥可以打包出来的代码可以跑在浏览器上呢?相信大家有会说用babel-loader转义,把es6代码转化成浏览器认识的es5代码,可是大家都知道babel是如何转化es6代码的吗?里面究竟发生了什么不可告人的秘密,今天就好好探索下。
开宗明义,先来讲下babel的核心原理:
Babel 解析成 AST,然后插件更改 AST,最后 Babel 输出代码
具体是:
1 babylon 解析器把代码字符串转化为 AST(abstract syntax tree)树
2 babel-traverse 对 AST 树进行解析遍历出整个树的path
3 plugin 转换出新的 AST 树
4 生成新的代码字符串
下面来尝试实现一个插件,作用是把
const res = 1 + 1;
// 转化为
const res = 2;
babel 插件的核心是需要返回一个 function,function 内返回 visitor
module.export = function() {
return {
visitor: {
}
}
}
visitor (访问者)是对各类型的 AST 节点做处理的地方,问题是 visitor 怎么知道 Babel 生成了的 AST 有哪些节点?
答案是可以通过打印Babel转化过后的代码。这里可以帮助你快速解决代码转化问题:
转化后的样子如下图:
一定有小伙伴会问,为什么会要有 AST 这个东西?
但是语言的的编译过程需要经历两个阶段:
- 词法分析
- 语法分析
AST 就是等于把一些列的单词都拆出来,这样的好处是让计算机更容易识别,AST 充当了翻译官的角色,让编写代码的人和机器都很容易知道代码的含义。
语法分析,就是把相关的单词组合起来,就是英文单词都需要组合成句子短语才有其意义,计算机也是如此。
好了,交代上面 AST 的作用后,正式进入编写 babel 插件的工作。
如上,可以看到const res = 1 + 1;其中1 + 1是一个BinaryExpression节点,那么接下来,就来处理这个节点。
const 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;
default:
break;
}
}
if (result !== undefined) {
path.replaceWith(t.numericLiteral(result));
}
}
};
module.exports = function (params) {
return {
visitor
}
}
哈哈,以上就是最简单的一个babel插件了,
具体如何使用呢?
-
配置到node_modules
可以新建一个文件夹叫babel-plugin-simple-plus,另外在其下面新建一个文件叫做index.js,内容为上面的代码。具体如图。
-
在.babelrc加入配置项
{
"presets": ["@babel/preset-env"],
"plugins": [
"@babel/plugin-proposal-class-properties",
"simple-plus"
]
}
只需要加入“simple-plus”配置即可。
小结:
其他更多的 babel 插件玩法,需要各位高玩自己好好琢磨(自己也需要继续探索更多高深用法),可以根据项目的需要,写出适合项目的 babel 插件,提高工作效率比什么都重要哈,在这里面还了解了下编译原理,仔细读了下,发现也没有一开始的恐惧感,其实编译最核心还是把代码字符串告诉计算机,使得计算机认识我们平常编写的代码,上面AST就很大程度上帮助我们解决这类问题。