Babel-handbook插件
babelcompiler bundlertool
Babel
作为source to source
的转换编辑器(transpiler)转换过程主要分为三步:
- parse: 通过
parser
把源码转换成抽象语法树(AST
),词法分析根据规则拆分成各个token
再通过语法分析将token
递归组装成可用的AST
- transform: 通过相应
visitor
函数遍历AST
调用各种transform
插件对AST
进行操作修改 - generate: 把转换后的
AST
生成对应结构的字符串并拼接还会并生成sourcemap
抽象语法树(AST)
AST节点组成
处理过程中每一步都涉及到创建或是操作抽象语法树,babel使用基于ESTree标准的ast
js
function square(n) { return n * n;}
解析后的ast如下:
json
{ type: "FunctionDeclaration", id: { type: "Identifier", name: "square" }, params: [{ type: "Identifier", name: "n" }], body: { type: "BlockStatement", body: [{ type: "ReturnStatement", argument: { type: "BinaryExpression", operator: "*", left: { type: "Identifier", name: "n" }, right: { type: "Identifier", name: "n" } } }] }}
每个层级都有相同的结构:
json
{ type: "FunctionDeclaration", id: {...}, params: [...], body: {...}}
json
{ type: "Identifier", name: ...}
json
{ type: "BinaryExpression", operator: ..., left: {...}, right: {...}}
AST节点类型
节点类型包括:
Literals
Programs
Functions
Statements
Declarations
Misc
Expressions
Template Literals
Patterns
Patterns
Classes
Modules
具体构成及说明文档位于@babel/parser ast specification
AST节点属性
json
{ type: ..., start: 0, end: 38, loc: { start: { line: 1, column: 0 }, end: { line: 3, column: 1 } }, ...}
转换过程
语法解析
通过@babel/parser
将源码解析(词法分析、语法分析)为ast
,具体options配置项决定产出形式
js
require('@babel/parser').parse("soucecode", { sourceType: 'module', plugins: [ 'jsx' ]})
AST遍历
通过@babel/traverse
进行遍历ast
节点进行增删改,在遍历过程中通过访问者模式(visitor)
对指定的节点类型例如:FunctionDeclaration进行访问,同时可使用@babel/types
提供的工具函数进行节点判断及生成
ts
interface traverse { ast: AST visitor: (path, state) => {}}
js
traverse(ast, { FunctionDeclaration: { enter(path, state) {}, // 进入节点时调用 exit(path, state) {} // 离开节点时调用 }})
// 只指定一个函数那就是enter阶段调用traverse(ast, { FunctionDeclaration(path, state) {} // 进入节点时调用})
// 多个ast类型节点处理,通过"|"// 通过别名指定离开各种 Declaration 节点时调用traverse(ast, { 'FunctionDeclaration|VariableDeclaration'(path, state) {}})
path
记录了节点间相互关系的路径,同时提供了很多属性和方法方便遍历操作
path.scope
包含了js中能生成作用域(模块、函数、块)等所形成的作用域链
state
保存了在传递到对应节点是的options和file以及共享数据
转换后生成
使用@babel/generator
将ast
生成代码字符串
ts
function (ast: Object, opts: Object, code: string): {code, map}
js
import generate from "@babel/generator";
const { code, map } = generate(ast, { sourceMaps: true })
同时可使用@babel/code-frame
在生成过程中打印报错代码位置
js
import { codeFrameColumns } from "@babel/code-frame";
const rawLines = `class Foo { constructor()}`;const location = { start: { line: 2, column: 16 } };
const result = codeFrameColumns(rawLines, location, { /* options */});
console.log(result);