Open fi3ework opened 6 years ago
目前前端代码的编译器基本都是 Babel,更确切地说是源码到源码的编译器,通常也叫做“转换编译器(transpiler)”。 意思是说你为 Babel 提供一些 JavaScript 代码,Babel 更改这些代码,然后返回给你新生成的代码。实际上 Babel 就是完成了"ES6 代码的字符串 -> ES5 代码的字符串"的转化,虽然输入输出都字符串,但是整个过程需要经历三个阶段:
Babylon 解析和理解 JavaScript 代码
babel-traverse 分析和修改 AST
babel-generator 将 AST 转换回正常的代码
抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。之所以说语法是“抽象”的,是因为这里的语法并不会表示出真实语法中出现的每个细节。
目前来说,已经有 babylon(现在已变成 babel/core)来帮助我们完成第一步的 AST 生成工作和第三步的再建
Babel 使用一个基于 ESTree 并修改过的 AST,它的内核说明文档可以在[这里](https://github. com/babel/babel/blob/master/doc/ast/spec. md)找到。.
其中第二步变化,包括各种 babel 插件就在 AST 的这个阶段进行操作。
上面已经提到了 babel 的 plugin 是第二步中,插件拿到代码的 AST 进行处理再返回。
先介绍 Babel 插件的基本格式:
export default function({ types: t }) { return { visitor: { // visitor contents Identifier(path, state) {/* do something */}, ASTNodeTypeHere(path, state) {/* do something */} } }; };
Babel 通过 babel-traverse 来遍历各个节点,我们在 visitor 中的属性的 key 就是会被遍历到并处理的 AST 中的节点名,并且还能传入这个节点的两个参数:path 和 state。最外层的函数传入的是 babel,一般直接解构获得 babel-types 来辅助进行类型判断。
Path 是表示两个节点之间连接的对象。当你有一个 Identifier() 成员方法的访问者时,你实际上是在访问路径而非节点。 通过这种方式,你操作的就是节点的响应式表示(译注:即路径)而非节点本身。
Identifier()
path 中包含了我们可以修改的属性,也包含添加、更新、移动和删除节点有关的其他很多方法。
state 是从 plugin 的配置文件中传递的参数。
我们来看一个 babel 官方的插件的实现:babel-plugin-transform-undefined-to-void ,有些代码中允许 undefined 被修改,这个插件的功能是使用 void 0 代替 undefined 来保证 undefined 的正确性。
undefined
void 0
module.exports = function({ types: t }) { const VOID_0 = t.unaryExpression("void", t.numericLiteral(0), true); // 生成 `void 0` 对象 return { name: "transform-undefined-to-void", visitor: { ReferencedIdentifier(path) { // 如果是被引用的标识符 if (path.node.name === "undefined") { // 如果被赋值的对象是 undefined path.replaceWith(VOID_0); // 将 undefined 替换为 `void 0` } } } }; };
整体流程参考 minipack,minipack 写了很详细的注释,也有 中文版 的,不再过多重复。
这里再整理一下整个流程的思路:
function(require, modules, export){ code }
抽象语法树
minipack
roid
理解 Babel 插件
astexplorer
Babel 插件手册
Babel for ES6? And Beyond!
babel/parser (babylon) AST node types
【译】通过开发 Babel 插件理解抽象语法树(AST)
简要分析前端代码从 Babel 编译到打包的流程
Babel
目前前端代码的编译器基本都是 Babel,更确切地说是源码到源码的编译器,通常也叫做“转换编译器(transpiler)”。 意思是说你为 Babel 提供一些 JavaScript 代码,Babel 更改这些代码,然后返回给你新生成的代码。实际上 Babel 就是完成了"ES6 代码的字符串 -> ES5 代码的字符串"的转化,虽然输入输出都字符串,但是整个过程需要经历三个阶段:
Babylon 解析和理解 JavaScript 代码
babel-traverse 分析和修改 AST
babel-generator 将 AST 转换回正常的代码
AST
抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。之所以说语法是“抽象”的,是因为这里的语法并不会表示出真实语法中出现的每个细节。
目前来说,已经有 babylon(现在已变成 babel/core)来帮助我们完成第一步的 AST 生成工作和第三步的再建
其中第二步变化,包括各种 babel 插件就在 AST 的这个阶段进行操作。
Babel 插件
上面已经提到了 babel 的 plugin 是第二步中,插件拿到代码的 AST 进行处理再返回。
先介绍 Babel 插件的基本格式:
Babel 通过 babel-traverse 来遍历各个节点,我们在 visitor 中的属性的 key 就是会被遍历到并处理的 AST 中的节点名,并且还能传入这个节点的两个参数:path 和 state。最外层的函数传入的是 babel,一般直接解构获得 babel-types 来辅助进行类型判断。
path 中包含了我们可以修改的属性,也包含添加、更新、移动和删除节点有关的其他很多方法。
state 是从 plugin 的配置文件中传递的参数。
我们来看一个 babel 官方的插件的实现:babel-plugin-transform-undefined-to-void ,有些代码中允许
undefined
被修改,这个插件的功能是使用void 0
代替undefined
来保证undefined
的正确性。打包
整体流程参考 minipack,minipack 写了很详细的注释,也有 中文版 的,不再过多重复。
这里再整理一下整个流程的思路:
function(require, modules, export){ code }
中,在执行每个模块的时候按照相同的函数签名传入对应参数即可。参考
抽象语法树
minipack
roid
理解 Babel 插件
astexplorer
Babel 插件手册
Babel for ES6? And Beyond!
babel/parser (babylon) AST node types
【译】通过开发 Babel 插件理解抽象语法树(AST)