什么是 babel

Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

什么是抽象语法树(AST)

在计算机科学中,抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。 它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。 之所以说语法是“抽象”的,是因为这里的语法并不会表示出真实语法中出现的每个细节。

对于 AST 的相关介绍:

推荐的介绍链接:

Leveling Up One’s Parsing Game With ASTs

中文翻译: https://segmentfault.com/a/1190000038511186

维基百科里的介绍: https://en.wikipedia.org/wiki/Abstract_syntax_tree

babel 的简单使用

相关 api 可以参考文档: https://babeljs.io/docs/en/babel-core#parse

使用 babel 的 API 将代码解析成 ast:

var babel = require("@babel/core");
const code = `const a = 1 + 2;`
// code 解析成 ast
const result = babel.transformSync(code, {ast: true});
console.log(result.ast)

当然 ast 也可以转换成代码:

const { code } = babel.transformFromAstSync(result.ast, { presets: ["minify"], babelrc: false, configFile: false,});
console.log(code)

在这个在线网站,你可以更加直接地看到 code 和 ast 的比较:

https://lihautan.com/babel-ast-explorer

const n = 1 的 ast:

-program:Program{
sourceType:"module" -body:[ -VariableDeclaration { -declarations:[ -VariableDeclarator{ -id:Identifier{ name:"n" } -init:NumericLiteral{ -extra:{ rawValue:1 raw:"1" } value:1 } } ] kind:"const" } ] directives:[]}

babel 插件:

var babel = require("@babel/core");
const code = 'const n = 1';
const output = babel.transformSync(code, {
plugins: [ function myCustomPlugin() {
return {
visitor: {
Identifier(path) {
// 在这个例子里我们将所有变量 `n` 变为 `x` if (path.isIdentifier({ name: 'n' })) {
path.node.name = 'x'; }
},
},
};
},
],});
console.log(output.code);
// const x = 1;

通过 babel 的插件我们可以对代码进行随心所以的修改

关于 visitor 使用的是访问者模式, 在遍历阶段,babel会先进行深度优先遍历来访问AST的每一个节点。你可以为访问指定一个回调函数,然后每当访问某个节点的时候,babel会调用这个函数,并给函数传入当前访问的节点。

现在我们添加另一个函数: NumericLiteral, 在刚刚的 ast 中我们可以看到 const n = 1 是有 NumericLiteral 此节点的

function myCustomPlugin() {
return {
visitor: {
Identifier(path) {
console.log('identifier');
},
NumericLiteral(path) {
console.log('NumericLiteral');
},
},
};
}

运行 plugin.js, 打印结果:

Identifier
NumericLiteral
const x = 1;

即在碰到此节点的时候 就会触发插件中对应节点的回调, 关于回调函数的 path 可以在此文档中查看: https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#paths

修改表达式

在插件方法 NumericLiteral 上添加操作:

visitor: {
// 省略其他方法 NumericLiteral(path) {
console.log('NumericLiteral');
const newNode = babel.types.binaryExpression('+', babel.types.NumericLiteral(path.node.value), babel.types.NumericLiteral(10));
path.replaceWith(newNode);
path.skip(); // 因为我们新增加了一个 NumericLiteral, 所以插件会检测到, 并且又会触发此回调,造成无限循环 // skip 的作用就是跳过对当前路径子节点的访问 }
}

这里我们新建了一个 binaryExpression, 将 const x = 1 转换为 const x = 1 + 10

这是关于 babel.types 的文件: https://www.babeljs.cn/docs/babel-types

本文代码记录: https://github.com/Grewer/JsDemo/tree/master/babel2AST

参考资料

https://lihautan.com/step-by-step-guide-for-writing-a-babel-transformation/

babel 与 ast的更多相关文章

  1. 写一个为await自动加上catch的loader逐渐了解AST以及babel

    为什么要写这个loader 我们在日常开发中经常用到async await去请求接口,解决异步.可async await语法的缺点就是若await后的Promise抛出错误不能捕获,整段代码区就会卡住 ...

  2. es6转码器-babel

    babel 基本使用 安装转码规则 # ES2015转码规则 $ npm install --save-dev babel-preset-es2015 # react转码规则 $ npm instal ...

  3. [转] babel的使用

    一.配置文件.babelrc .babelrc 文件存放在项目的根目录下. { "presets": [], "plugins": [] } presets 字 ...

  4. babel那些事儿

    从前,一提到新东西,我的反应就是兼容性好不好,如果不能满足产品经理的需求,就还是用保守的方式实现吧.毕竟前端开发是一件很灵活的事,怎么写都行,至于为何会用某种方法,一定是综合考虑兼容性,性能,用户体验 ...

  5. babel的使用(关于使用async报错的问题)

    一.配置文件.babelrc .babelrc 文件存放在项目的根目录下. { "presets": [], "plugins": [] } presets 字 ...

  6. Babel 入门教程

    Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行. 这意味着,你可以现在就用 ES6 编写程序,而不用担心现有环境是否支持.下面是一个例子. // 转码前 inpu ...

  7. Babel 是干什么的

    首先babel是干什么的?Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行. babel就是为了支持原有的旧的环境. 一.配置文件.babelrc Babel的配置 ...

  8. 【Babel】293- 初学 Babel 工作原理

    戳蓝字「前端技术优选」关注我们哦! 前言 babel Babel 对于前端开发者来说应该是很熟悉了,日常开发中基本上是离不开它的. 已经9102了,我们已经能够熟练地使用 es2015+ 的语法.但是 ...

  9. 你必须要知道的babel二三事

    1. 什么是babel 本文基于的babel版本是7.11.6,本文所有示例github Babel is a toolchain that is mainly used to convert ECM ...

随机推荐

  1. 深度分析:那些Java中你一定遇到过的问题,一次性帮你搞定!深度分析:那些Java中你一定遇到过的问题,一次性帮你搞定!

    1.java中==和equals和hashCode的区别 基本数据类型的比较的值相等.类的比较的内存的地址,即是否是同一个对象,在不覆盖equals的情况下,同比较内存地址,原实现也为 == ,如St ...

  2. 如何用Camtasia将喜欢的视频做出复古的感觉

    不知道各位可有看老电影的习惯,我个人觉得一些老电影那种别具一格的画面感是非常吸引人的韵味,尽管其色彩不是很鲜艳,但是这种黑白的感觉,对于现在的我们,往往有着不一样的吸引力.于是,我就尝试着用Camta ...

  3. 怎么借助CrossOver安装想要的Windows程序

    面对安装双系统时的繁琐步骤,以及虚拟机软件那庞大的体积,CrossOver的出现,让一切都变得简单起来. CrossOver自带的一系列的Windows应用,涵盖游戏软件.办公软件.设计软件等多个种类 ...

  4. 唯一key的生成规则,可自己视情况改动

    <?php function getMillisecond() { $time = explode ( " ", microtime ()); $time = $time[1 ...

  5. 通过Consul Raft库打造自己的分布式系统

    通用的CP系统有etcd和consul, 通用的对立面就是专用系统. 所以在某些场合是有这种需求的. 然而etcd embed的可用性极差, Windows上面跑会出现各种问题, 而且不能定制协议, ...

  6. dubbo协议之请求头编码器

    开局一张图,内容全靠XXXXX.... 如图是dubbo协议的格式 encodeRequest进来会先去channel对象中取url的Parameters的"serialization&qu ...

  7. 跟随杠精的视角一起来了解Redis的主从复制

    不想弹好吉他的撸铁狗,都不是好的程序猿 虽然说单机的Redis性能很好,也有完备的持久化机制,那如果你的业务体量真的很大,超过了单机能够承载的上限了怎么办?不做任何处理的话Redis挂了怎么办?带着这 ...

  8. 推荐系统实践 0x09 基于图的模型

    用户行为数据的二分图表示 用户的购买行为很容易可以用二分图(二部图)来表示.并且利用图的算法进行推荐.基于邻域的模型也可以成为基于图的模型,因为基于邻域的模型都是基于图的模型的简单情况.我们可以用二元 ...

  9. linux 权限提升

    1.内核提权,根据版本搜索相应exp 查看操作系统版本命令 uname –a lsb_release –a cat /proc/version 查看内核版本 cat /etc/issue 查看发行类型 ...

  10. JZOJ8月10日提高组反思

    JZOJ8月10日提高组反思 T1 没想到怎么打 就去打暴力了 本来想拿个30不错了 结果\(AC\)了 话说回来,数据也挺小的 T2 不AC便爆0 就一个数据点 给不给打暴力的人活了 正解是状压DP ...