疑问
- path API的官方文档?
- 不晓得有没有官方文档,但是后文“Traverse 的 path、scope、visitor”中有一个已经很详尽的版本了,基本够用。
- 通过@babel/types创建了AST元素后,如何插入AST语法树对应位置?
- 利用@babel/parser的path API
- 如何删除/修改指定AST元素?
- 利用@babel/parser的path API
- @babel/code-frame工作方式不明?我的理解babel到头来讲只是字符串转换,为什么可以有报错警告?不需要和编辑器结合才能警告么?
- 有了@babel/core还需要单独使用其他包么?
- 在babel-plugin-import中,并没有显示地使用任何以下出现的babel包,却处处可见这些babel包api的影子?bebel-plugin-import的实现原理是什么?和这些babel包的关系是什么?
- babel-plugin-import的结构,和@babel/traverse的转换函数的visitor的结构非常接近,这是因为babel-plugin-import是一个标准的babel plugin结构,后文会提到:
- 没有显示引用却随处可见影子的原因是因为,babel插件的第一个参数暴露出了这些包的内部API,与这些babel包的关系是封装与原生。
是否可以自定义plugin和preset?babel-plugin-import的实现原理就是自定义的plugin和preset么?
摘要
版本
parse 阶段
- @babel/parser,功能是把源码转成 AST
- transform 阶段
- @babel/traverse:调用 visitor 函数遍历AST
- @babel/types :修改AST
- @babel/template:批量创建 AST
- generate 阶段
- @babel/generate:AST->code,同时生成 sourcemap
其他
- @babel/code-frame:中途遇到错误想打印代码位置
@babel/parser
https://babel.docschina.org/docs/en/babel-parser/
有两个 api:parse 和 parseExpression
- @babel/code-frame:中途遇到错误想打印代码位置
parse 返回整个 AST
- parseExpression 返回表达式的 AST
options是核心,具体api可查看文档。其实主要分为两类(parse的内容是什么、以什么方式parse)function parse(input: string, options?: ParserOptions): File
function parseExpression(input: string, options?: ParserOptions): Expression
最常用的 option 就是 plugins、sourceType 这两个,比如要 parse tsx 模块,那么就可以这样来写:require("@babel/parser").parse("code", {
sourceType: "module",
plugins: [
"jsx",
"typescript"
]
});
@babel/traverse
parent 指定要遍历的 AST 节点,opts 指定 visitor 函数。 ```javascript // 进入 FunctionDeclaration 节点时调用 traverse(ast, { FunctionDeclaration: {function traverse(parent, opts)
} })enter(path, state) {}, // 为对象,则可以明确指定 enter 或者 exit 时的处理函数
exit(path, state) {}
// 默认是进入节点时调用,和上面等价 traverse(ast, { FunctionDeclaration(path, state) {} // 为函数,那么就相当于是 enter 时调用的函数 })
两个参数:
<a name="YE4sb"></a>
### (1)path
path是遍历过程中的路径,会保留上下文信息,有很多属性和方法(核心)
- path.node 指向当前 AST 节点
- path.get、path.set 获取和设置当前节点属性的 path
- path.parent 指向父级 AST 节点
- path.getSibling、path.getNextSibling、path.getPrevSibling 获取兄弟节点
- path.find 从当前节点向上查找节点
- path.scope 获取当前节点的作用域信息
- path.isXxx 判断当前节点是不是 xx 类型
- path.assertXxx 判断当前节点是不是 xx 类型,不是则抛出异常
- path.insertBefore、path.insertAfter 插入节点
- path.replaceWith、path.replaceWithMultiple、replaceWithSourceString 替换节点
- path.remove 删除节点
- path.skip 跳过当前节点的子节点的遍历
- path.stop 结束后续遍历
<a name="ivoMx"></a>
### (2)state
遍历过程中在不同节点之间传递数据的机制<br />有点this的味道,babel-plugin-import里大量使用了这种方式进行通信:[https://github.com/umijs/babel-plugin-import/blob/d21264e4fb9c9f60041ceed748177db16f347ad7/src/Plugin.js#L55](https://github.com/umijs/babel-plugin-import/blob/d21264e4fb9c9f60041ceed748177db16f347ad7/src/Plugin.js#L55)
<a name="BQLbY"></a>
## @babel/types
遍历 AST 的过程中需要创建一些 AST 和判断 AST 的类型.<br />isXxx 会返回 boolean 表示结果,而 assertXxx 则会在类型不一致时抛异常。<br />所有的 AST 的 build、assert 的 api 可以在 [babel types 文档](https://link.juejin.cn/?target=https%3A%2F%2Fbabeljs.io%2Fdocs%2Fen%2Fbabel-types%23api)中查,如:<br /><br />通常要先知道所操作的节点是什么AST类型,再选择对应的判断/创建方法。
<a name="q2EtZ"></a>
## @babel/templete
[https://babel.docschina.org/docs/en/babel-template/](https://babel.docschina.org/docs/en/babel-template/)<br />看名字就晓得是模板,基础用法:<br /><br />_无论是此处的templete占位符还是@babel/traverse的state用法都让我想起Vue_<br />其他用法:
- 根据模版创建整个 AST
- template.ast
- template.program
- 返回的 AST 的根节点是 Program。
- 知道具体创建的 AST 的类型
- template.expression、template.statement、template.statements 等方法创建具体的 AST
- 更多详见文档,估计最常用的还是基础用法。
<a name="EPWJX"></a>
## @babel/generator
[https://babel.docschina.org/docs/en/babel-generator/](https://babel.docschina.org/docs/en/babel-generator/)
```javascript
import { parse } from "@babel/parser";
import generate from "@babel/generator";
const code = "class Example {}";
const ast = parse(code);
const output = generate(
ast,
{
/* options */
},
code
);
- 第一个参数是要打印的 AST
- 第二个参数是 options,指定细节
- options 中常用的是 sourceMaps,开启了这个选项才会生成 sourcemap
第三个参数当多个文件合并打印的时候需要用到
@babel/code-frame
有错误信息要打印的时候,需要打印错误位置的代码时使用。
?工作原理、表现形式不明@babel/core
整合以上全部
options 主要配置 plugins 和 presets,指定具体要做什么转换:transformSync(code, options); // => { code, map, ast }
transformFileSync(filename, options); // => { code, map, ast }
transformFromAstSync(
parsedAst,
sourceCode,
options
); // => { code, map, ast }
tips
- transformXxx 的 api,已经被标记为过时了,后续会删掉,不建议用,直接用 transformXxxSync 和 transformXxxAsync
- 还有一个 createConfigItem 的 api,用于 plugin 和 preset 的封装(后面的章节涉及,感觉这才是重点)