介绍
Babel 是一款将未来的 JavaScript 语法编译成过去语法的 Node.js 工具。本文从 2019 年 11 月的 master 分支源码入手,介绍 Babel 在解决这类问题时是如何划分模块。
Babel 的模块划分
其中 babel-loader 隶属于 webpack,不在 Babel 主仓库。
框架层
常见的编译器
常见的解析器有 acorn、@babel/parser (babylon)、flow、traceur、typescript、uglify-js 等,各自的 AST 语法树大致相同。
@babel/parser 的实现
关键词说明
- Literal:字面量。包括:Boolean、Number、String。
- Identifier:识别量。包括变量名、undefined、null 等。
- Val:值。常分为左值和右值。左值表示一个可以被赋值的节点,如:[a] 等,左值往往是 Pattern、Identifier 等类型。右值表示一个代表具体值的节点,如:b.c 等,右值往往是 Expression、Identifier、Literal 等类型。左值与右值之间通过等号联结,代表赋值表达式,如:[a] = b.c。
- Declaration:赋值。
- Expression:表达式。常用来表示右值。常见的 Expression 有:MemberExpression、BinaryExpression、UnaryExpression、AssignmentExpression、CallExpression 等。
- Statement:语句。往往由 Expression 组合而成。常见的 Statement 有:ExpressionStatement。
- Program:程序。所有代码在一个 Program 下,一个 Program 包含多个并列的 Statement。
let c = 0;
while (a < 10) {
const b = a % 2;
if (b == 0) {
c++;
}
}
console.log(c);
上面的这段代码通过 @babel/parser 解析后得到的 AST 语法树如下:
@babel/parser 的 9 层继承
- Parser:初始化
- StatementParser:解析语句,拼装成 program,代码大约有 2100+ 行
- ExpressionParser:解析表达式,代码大约有 2400+ 行
- LValParser:左值处理,将节点变为可以被赋值的节点。如:ArrayExpression 转为 ArrayPattern
- NodeUtils:AST 节点操作,如复制等
- UtilParser:工具函数,如判断行末等
- Tokenizer:词法分析,大约有 1400+ 行
- LocationParser:文件位置信息
- CommentsParser:解析注释
- BaseParser:插件能力
大部分模块代码量在百行左右,其中 StatementParser、ExpressionParser 和 Tokenizer 有较多复杂逻辑。
@babel/traverse
提供遍历 AST 语法树的能力,如:
traverse(ast, {
FunctionDeclaration: function(path) {
path.n