Open AnnVoV opened 5 years ago
先看效果,写了一个小例子,请点击查看 https://astexplorer.net/#/gist/49a1bb9cc81e392220ffd998ff47162c/4728dec0c4645e40c58426886bc2069c959544e4
查找ast相关资料,看到别人引用资源里有一个ppt,《how writing a babel plugin is like... jQuery》看了一遍发现,真香!下面我就按照我的理解总结一下ppt里面的内容。通过了解如何开发一个babel插件,也能让我们更好地理解ast. 后面可以不看,重点推荐下面这两个资料:
在开始往下面看之前,为了对ast节点类型有更全面的认识,推荐阅读下这个同学写的文章:https://github.com/Pines-Cheng/blog/issues/53 Babylon 与 JavaScript 抽象语法树
Babel is a javascript compiler。
Babel 是一个通用的,多用途的Javascript 编译器
整个ppt最犀利的观点就是:
Babel::javascript jQuery::DOM Babel turns the code you have into the code you need
dom 之于 jQuery 同 javascript 之于 Babel
babel 中的几个核心模块:
export default babel => { return { visitor:{...} } }
export default function(babel) { const t = babel.types; return { visitor: { BinaryExpression(path) {...}, Identifier(path) {...}, FunctionDeclaration(path) {...}, ClassDeclaration(path) {...}, } } }
当Babel遍历ast时,会查看每一个节点,当发现visitor对象上有对应的方法时,会调用这个方法,并且把对应的上下文传递进去。
var a = 2**3 // 源代码转换为 var a = Math.pow(2, 3); // 目标代码
上面通过babel 插件如何实现呢?
我们利用https://astexplorer.net 这个网址可以查看到源代码对应的ast结构,让我们知道我们需要的各个节点类型。
export default function(babel) { // 插件大体结构是一样的 const t = babel.types; return { visitor: { // 2**3 是一个二元表达式 BinaryExpression(path) { // console.log(path); 可以把对应路径打印出来看看 if (path.node.operator !== '**') { return; // 如果节点对应的操作不是** 不做任何处理 } const {left, right} = path.node; // 获取表达式左右两项 } } } }
最终我们希望把2**3 替换为一个函数调用Math.pow(2,3), 所以要看下Math.pow(2,3) 的ast 结构,同样利用上面那个网址
Math.pow(2,3)
// babel-type 手册https://babeljs.io/docs/en/next/babel-types.html t.callExpression( t.memberExpression( // 创建函数 t.identifier('Math'), t.identifier('pow'), ), [left, right] // 入参 );
这样就生成了一个Math.pow(2, 3)的函数调用节点
export default function(label) { const t = babel.types; return { visitor: { BinaryExpression(path) { if (path.node.operator !== '**') { return; } path.replaceWith(t.callExpression( t.memberExpression( t.identifier('Math'), t.identifier('pow') ), [left, right] )); } } } }
其实写babel插件的重点在于了解ast, 有了ast以后我们可以做很多事情,除了写bable插件,我们也可以去写eslint插件,本质是一样的,只是语法有些略微的区别。
module.exports = { meta: { docs: { description: "Disallow if statement without block", category: "Best Practices", recommended: true } }, create(context) { return { IfStatement(node) { if(isBlock(node.consequent) && isBlock(node.alternate)) { return; } context.report({ node, message: 'yo, y u non block?' fix: function(fixer) { // fix the code } }) function isBlock(n) { return !n || n.type === 'BlockStatement'; } } }; // 更复杂的babel插件参考 // https://juejin.im/post/5a17d51851882531b15b2dfc } };
参考资料: 1.how writing a babel plugin is like...(重要 非常棒) https://hzoo.github.io/babel-plugin-slides/assets/player/KeynoteDHTMLPlayer.html#0 2.Writing custom Babel and ESLint plugins http://slides.com/kentcdodds/a-beginners-guide-to-asts#/6 3.@babel/types babel的参考手册 4.通过开发 Babel 插件理解抽象语法树(AST) https://www.zcfy.cc/article/understanding-asts-by-building-your-own-babel-plugin 5.如何写一个eslint 插件(拓展) https://www.zcfy.cc/article/creating-an-eslint-plugin
最终效果
先看效果,写了一个小例子,请点击查看 https://astexplorer.net/#/gist/49a1bb9cc81e392220ffd998ff47162c/4728dec0c4645e40c58426886bc2069c959544e4
前言
查找ast相关资料,看到别人引用资源里有一个ppt,《how writing a babel plugin is like... jQuery》看了一遍发现,真香!下面我就按照我的理解总结一下ppt里面的内容。通过了解如何开发一个babel插件,也能让我们更好地理解ast. 后面可以不看,重点推荐下面这两个资料:
ast 基础
在开始往下面看之前,为了对ast节点类型有更全面的认识,推荐阅读下这个同学写的文章:https://github.com/Pines-Cheng/blog/issues/53 Babylon 与 JavaScript 抽象语法树
What is Babel?
Babel is a javascript compiler。
整个ppt最犀利的观点就是:
dom 之于 jQuery 同 javascript 之于 Babel
Compile Overview
babel 中的几个核心模块:
Write a Babel Plugin
A Plugin is just a function
AST Visitor Pattern
当Babel遍历ast时,会查看每一个节点,当发现visitor对象上有对应的方法时,会调用这个方法,并且把对应的上下文传递进去。
举个例子
上面通过babel 插件如何实现呢?
Step1 查看源代码ast 结构
我们利用https://astexplorer.net 这个网址可以查看到源代码对应的ast结构,让我们知道我们需要的各个节点类型。
Step2 获取源码对应结构
Step3 对源码结构进行替换
最终我们希望把2**3 替换为一个函数调用
Math.pow(2,3)
, 所以要看下Math.pow(2,3) 的ast 结构,同样利用上面那个网址这样就生成了一个Math.pow(2, 3)的函数调用节点
step4 节点替换
拓展
其实写babel插件的重点在于了解ast, 有了ast以后我们可以做很多事情,除了写bable插件,我们也可以去写eslint插件,本质是一样的,只是语法有些略微的区别。
参考资料: 1.how writing a babel plugin is like...(重要 非常棒) https://hzoo.github.io/babel-plugin-slides/assets/player/KeynoteDHTMLPlayer.html#0 2.Writing custom Babel and ESLint plugins http://slides.com/kentcdodds/a-beginners-guide-to-asts#/6 3.@babel/types babel的参考手册 4.通过开发 Babel 插件理解抽象语法树(AST) https://www.zcfy.cc/article/understanding-asts-by-building-your-own-babel-plugin 5.如何写一个eslint 插件(拓展) https://www.zcfy.cc/article/creating-an-eslint-plugin