You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
起初,JavaScript 与服务器语言不同,它没有办法保证对每个用户都有相同的支持,因为用户可能使用支持程度不同的浏览器(尤其是旧版本的 Internet Explorer)。如果开发人员想要使用新语法(例如 class A {}),旧浏览器上的用户只会因为 SyntaxError 的错误而出现屏幕空白的情况。
Babel 为开发人员提供了一种使用最新 JavaScript 语法的方式,同时使得他们不必担心如何进行向后兼容,如(class A {} 转译成 var A = function A() {})。
Babel是什么?我为什么要了解它?
1. 什么是babel ?
为了能用可爱的ES678910写代码,我必须了解它!
2. 可靠的工具来源于可怕的付出
August 27, 2018 by Henry Zhu
Babel开发团队这么辛苦的为开源做贡献,为我们开发者提供更完美的工具,我为什么不去了解它呢?
(OS:求求你别更啦.老子学不动啦~)
3. Babel担任的角色
August 27, 2018 by Henry Zhu
即使你自己没有使用它,但你的依赖很可能正在使用 Babel。怕不怕 ? 了解不了解 ?
Babel的运行原理
1.解析
解析步骤接收代码并输出 AST。 这个步骤分为两个阶段:词法分析(Lexical Analysis) 和 语法分析(Syntactic Analysis)。
1.词法分析
词法分析阶段把字符串形式的代码转换为 令牌(tokens) 流。
你可以把令牌看作是一个扁平的语法片段数组:
每一个 type 有一组属性来描述该令牌:
和 AST 节点一样它们也有 start,end,loc 属性。
2.语法分析
语法分析阶段会把一个令牌流转换成 AST 的形式。 这个阶段会使用令牌中的信息把它们转换成一个 AST 的表述结构,这样更易于后续的操作。
简单来说,解析阶段就是
Babel 使用 @babel/parser 解析代码,输入的 js 代码字符串根据 ESTree 规范生成 AST(抽象语法树)。Babel 使用的解析器是 babylon。
什么是AST
2.转换
转换步骤接收 AST 并对其进行遍历,在此过程中对节点进行添加、更新及移除等操作。 这是 Babel 或是其他编译器中最复杂的过程。
Babel提供了@babel/traverse(遍历)方法维护这AST树的整体状态,并且可完成对其的替换,删除或者增加节点,这个方法的参数为原始AST和自定义的转换规则,返回结果为转换后的AST。
3.生成
代码生成步骤把最终(经过一系列转换之后)的 AST 转换成字符串形式的代码,同时还会创建源码映射(source maps)。
代码生成其实很简单:深度优先遍历整个 AST,然后构建可以表示转换后代码的字符串。
Babel使用 @babel/generator 将修改后的 AST 转换成代码,生成过程可以对是否压缩以及是否删除注释等进行配置,并且支持 sourceMap。
实践前提
在这之前,你必须对Babel有了基本的了解,下面我们只简单的了解下babel的一些东西,以便于后面开发插件。
babel-core
babel-core是Babel的核心包,里面存放着诸多核心API,这里说下transform。
transform : 用于字符串转码得到AST 。
传送门
babel-types
Babel Types模块是一个用于 AST 节点的 Lodash 式工具库(译注:Lodash 是一个 JavaScript 函数工具库,提供了基于函数式编程风格的众多工具函数), 它包含了构造、验证以及变换 AST 节点的方法。 该工具库包含考虑周到的工具方法,对编写处理AST逻辑非常有用。
传送门
JS CODE -> AST
查看代码对应的AST树结构
Visitors (访问者)
当我们谈及“进入”一个节点,实际上是说我们在访问它们, 之所以使用这样的术语是因为有一个访问者模式(visitor)的概念。
访问者是一个用于 AST 遍历的跨语言的模式。 简单的说它们就是一个对象,定义了用于在一个树状结构中获取具体节点的方法。 这么说有些抽象所以让我们来看一个例子。
这是一个简单的访问者,把它用于遍历中时,每当在树中遇见一个 Identifier 的时候会调用 Identifier() 方法。
Paths(路径)
AST 通常会有许多节点,那么节点直接如何相互关联呢? 我们可以使用一个可操作和访问的巨大可变对象表示节点之间的关联关系,或者也可以用Paths(路径)来简化这件事情。
Path 是表示两个节点之间连接的对象。
在某种意义上,路径是一个节点在树中的位置以及关于该节点各种信息的响应式 Reactive 表示。 当你调用一个修改树的方法后,路径信息也会被更新。 Babel 帮你管理这一切,从而使得节点操作简单,尽可能做到无状态。
Paths in Visitors(存在于访问者中的路径)
当你有一个 Identifier() 成员方法的访问者时,你实际上是在访问路径而非节点。 通过这种方式,你操作的就是节点的响应式表示(译注:即路径)而非节点本身。
Babel插件规则
Babel的插件模块需要我们暴露一个function,function内返回visitor对象。
撸一个Babel ...插件 !!!
文件结构
首先,我们先创建一个package.json。
package.json
可以看到,我们首先下载了@babel/core作为我们的开发依赖,然后配置了npm run babel作为开发命令。
index.js
我们首先来实现 功能 1. let,const 声明 -> var 声明
我们通过传送门查看到上面代码对应的AST结构为
我们可以看到这句声明语句位于VariableDeclaration节点,我们接下来只要操作VariableDeclaration节点对应的kind属性就可以啦~
before.js
plugin.js
ok~ 我们来看看效果!
after.js
没错,就是这么吊!!!功能1搞定,接下来实现功能2. 箭头函数 -> 普通函数 (this指向暂不做处理~)
我们先来看看箭头函数对应的节点是什么?
我们通过传送门查看到上面代码对应的AST结构为
我们可以看到箭头函数对应的节点是ArrowFunctionExpression。
接下来我们再来看看普通函数对应的节点是什么?
我们通过传送门查看到上面代码对应的AST结构为
我们可以看到普通函数对应的节点是FunctionExpression。
所以我们的实现思路只要进行节点替换(ArrowFunctionExpression->FunctionExpression)就可以啦。
plugin.js
满怀激动的
after.js
惊不惊喜 ? 意不意外 ? 你以为这样就结束了吗 ? 那你就太年轻啦。
我们经常会这样写箭头函数来省略return。
我们来试试 这样能不能转义
GG.控制台飘红~
下面我直接贴下最后的实现,具体原因我觉得读者自己研究或许更有趣~
plugin.js
小功告成
源码地址
如果觉得有帮助到你,请给个star或者follow 支持下作者哈~接下来还会有很多干货哦!!!
参考文献
很棒的Babel手册
The text was updated successfully, but these errors were encountered: