03.babel-JS解析器梳理
# 0.前言
本文主要是梳理 Javascript 语法解析器的发展历史。
希望阅读完本篇内容后,可以清楚以下 parser 的逻辑

# 1. AST 标准的发展历史
Mozilla 在 MDN 上公布了火狐浏览器的 JS 引擎 SpiderMonkey(c++ 写的 js 引擎)的 parser api 和 AST 标准,所以当时最早的 JS parser ---- esprima (opens new window) 就是基于 SpiderMonkey 的 AST 标准来实现的,后来形成了 estree 标准 (opens new window)。
SpiderMonkey AST 标准
↓
JS parser - esprima → estree 标准
2
3
当然也不是所有的js parser 都是 estree 标准的,比如 terser、typescript 等都有自己的 AST 标准。
关系如下图所示:

# 2.纯 ECMAScript parser 解析器—— Esprima 和 acorn
ESprima:最早的ECMAScript parser的语法解析器,在早期支持绝对部分的ES6的语法解析。当时很多的前端领域的工具都 基于esprima开发的。acorn:- 但速度快于
esprima解析器。 - 支持插件化开发。
- 但速度快于
# 3【ESLint】解析器
预览:
espree - 内置解析器
- 1.0 版本:基于 esprima 封装
- 2.0 版本:基于 acorn 封装
@babel/eslint-parser - babel 解析器
@typescript-eslint/parser - ts 解析器
2
3
4
5
# 3.1 espree ——默认解析器
这是 eslint 的默认 parser。
2015年之后,es标准一年一个版本,而esprima的更新速度跟不上,它跟不上也就导致了依赖它的一系列工具都跟不上,所以eslint就fork了一份esprima,做了一些扩展。后期
espree 2.0基于acorn重新实现了,也使用acorn的插件机制来扩展语法。
使用方式:通过 env 来设定 ESlint 的默认 ECMAScript parser 的版本。
module.exports = {
env: {
// 支持浏览器环境
browser: true,
// 识别 CommonJS
node: true,
// 识别 ES 的代码,使用 ECMAScript 2021 自动设置 ecmaVersion parser 为 12,
es2021: true,
},
};
2
3
4
5
6
7
8
9
10
存在的问题:ESLint Github#exprerimental features (opens new window)
# 3.2 @babel/eslint-parser
传统的 espree 只能支持最新版本的 ECMAScript 标准,不支持如下:
stage-3ECMAScript标准。- 语法特性,如
jsx\flow\typescipt
此时可以 .eslintrc.js ,切换为 babel 解析器
npm i -D @babel/core @babel/eslint-parser
可通过 parseOptions 配置解析器选项。具体内容如下:
ecmaVersion: 这个配置和Acron的 ecmaVersion (opens new window) 是兼容的,可以配置ES + 数字(如 ES6)或者ES + 年份(如 ES2015),也可以直接配置为latest,启用最新的 ES 语法。sourceType: 默认为script,如果使用ES Module则应设置为moduleecmaFeatures: 为一个对象,表示想使用的额外语言特性,如开启jsx。
overrides: [
// 处理 JS 文件
{
files: ["**/*.{js,jsx}"], // 只处理 js 和 jsx 文件
parser: "@babel/eslint-parser", // 使用 babel 来解析 js 文件
parserOptions: {
sourceType: "module", // 支持 import/export
allowImportExportEverywhere: false,
ecmaFeatures: {
globalReturn: false,
},
},
},
]
2
3
4
5
6
7
8
9
10
11
12
13
14
# 3.3 @typescript-eslint/parser
同上,espree 不支持 typescript 语法,传统的做法,切换回 typescript 进行语法支持。
overrides: [
// 处理 TS 文件
{
files: ["**/*.{ts,tsx}"], // 只处理 ts 和 js 文件
parser: "@typescript-eslint/parser", // 能看懂 TypeScript
parserOptions: {
project: ["./tsconfig.json"],
},
extends: [
// typescript-eslint 的推荐规则,只是这些最佳规则都是针对 TS 的
"plugin:@typescript-eslint/recommended",
// tsconfig.json 里 Type Checking 的推荐规则
"plugin:@typescript-eslint/recommended-requiring-type-checking",
],
plugins: [
// 使用 typescript x eslint 的插件
"@typescript-eslint",
],
}
]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 4.@babel/parser
Babel 中有两个包可以用于解析 JavaScript 代码,一个是 @babel/parser,另一个是 babel-parser(之前的名字是 babylon)。
在
babel 4版本前,babylon基于acorn进行开发,但后续已经看不到acorn依赖,是直接通过fork的acorn进行修改。在
babel 7版本以前,babel使用了Babylon作为默认的Javascipt解析器。但随着balylon的停止维护,babel从7版本开始推出了一个新的解析器@babel/parser。其中
acorn和babylon都是由同一位开发人员创建,并且babylon在某些情况下具有更好的性能和处理能力。在
babel 7版本后,@babel/parser是Babel官方推荐的解析器,它是基于Acorn解析器的一个fork版本,支持最新的ECMAScript标准,也支持JSX和TypeScript。
发展脉络如下:
babel 4 ← acorn 解析器
babel 4-7 ← balyon 解析器(fork acorn 源码)
babel 7 ← @babel/parser
2
3
其中,@babel/parser 基于 acorn 插件对 estree AST 做了如下扩展:
- 把
Literal替换成了StringLiteral、NumericLiteral、 BigIntLiteral、 BooleanLiteral、 NullLiteral、 RegExpLiteral - 把
Property替换成了ObjectProperty和ObjectMethod - 把
MethodDefinition替换成了ClassMethod Program和BlockStatement支持了directives属性,也就是'use strict'等指令的解析,对应的ast是Directive和DirectiveLiteralChainExpression替换为了ObjectMemberExpression和OptionalCallExpressionImportExpression替换为了CallExpression并且callee属性设置为Import
文档地址:https://babeljs.io/docs/babel-parser#output (opens new window)
# 3.总结
这一节我们了解了 ECMAScript parser 的历史,基于火狐浏览器的 JS 引擎 SpiderMonkey 的 AST 标准,制定了 espree 的标准,最早的 estree 标准的实现是 esprima。
但是随着 es2015 开始一年一个版本,esprima 的迭代速度逐渐跟不上了,这时候 acorn 流行起来,因为速度更快,而且支持插件扩展。
于是 espree、babel parser(babylon) 等都基于 acorn 来实现各自的 parser。虽然 estree 系列的 js parser 挺多的,但也不是全部,terser、typescript 等都是用自己的 AST。