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-3
ECMAScript
标准。- 语法特性,如
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
则应设置为module
ecmaFeatures
: 为一个对象,表示想使用的额外语言特性,如开启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
和DirectiveLiteral
ChainExpression
替换为了ObjectMemberExpression
和OptionalCallExpression
ImportExpression
替换为了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
。