【babel 】 编译流程

369 阅读2分钟

编译流程

parse

通过parse 转成AST语法树。 具体是把源代码转成转成机器能够理解的AST,这个过程分为词法分析语法分析

词法分析

我们要源码把它分成一个个不能细分的单词(token)的过程称为词法分析

语法分析

我们把token 进行递归的组装,生成AST的过程称为词法分析

AST

AST.png

parse的API

  • @babel/parser

示例

const parser = require('@babel/parser');
const ast = parser.parse(sourceCode, {
    sourceType: 'unambiguous', // "script" | "module" | "unambiguous"
    plugins: ['jsx']
});
  • sourceType的属性值 unambiguous :根据据内容是否有 import 和 export 来确定是否解析 es module 语法 module: module 是解析 es module 语法 script: 其他都是script

  • plugins

如果要解析tsx 模块,那么可以这样来写

require("@babel/parser").parse("code",
{ sourceType: "module",
    plugins: [ "jsx", "typescript" ]
 })
  • parse 类型声明
export function parse(
  input: string,
  options?: ParserOptions
): ParseResult<import("@babel/types").File>;

ParserOptions

transform

遍历AST,调用transform的各种API进行增删改查,遍历的过程中处理到不同的 AST 节点会调用注册的相应的 visitor 函数,visitor 函数里可以对 AST 节点进行增删改

transform的API

  • @babel/traverse: 遍历 AST
traverse(ast, {
    CallExpression:{
    enter(path,state){}
     }
    }
});
traverse(ast, {
    CallExpression(path, state) {
       ...
       }
    }
});

上面两者等价

  • @babel/types: 遍历 AST 的过程中需要创建一些 AST 和判断 AST 的类型
const types = require('@babel/types');
traverse(ast, {
    CallExpression(path, state) {
        if ( types.isMemberExpression(path.node.callee)) {
          
        }
    }
});
  • @babel/template: 简化 AST 创建逻辑

可以遍历 AST,并调用 visitor 函数修改 AST,修改 AST 自然涉及到 AST 的判断、创建、修改等, 这时候就需要 @babel/types 了,当需要批量创建 AST 的时候可以使用 @babel/template 来简化 AST 创建逻辑

generate

把AST生成目标代码,并且转换成sourcemap

generate的API

  • @babel/generate: 把 AST 打印为目标代码字符串,同时生成 sourcemap
function (ast: Object, opts: GeneratorOptions, code: string): {code, map}

类型声明

export default function generate(
    ast: t.Node,
    opts?: GeneratorOptions,
    code?: string | { [filename: string]: string },
): GeneratorResult;

options 中常用的是 sourceMaps,开启了这个选项才会生成 sourcemap

const { code, map } = generate(ast, { sourceMaps: true })
  • @babel/code-frame: 中途遇到错误想打印代码位置的时候
const result = codeFrameColumns(rawLines, location, {
  /* options */
});

@babel/core

基于上面的包完成 babel 整体的编译流程

const { transformFileSync } = require('@babel/core');

transformSync(code, options); // => { code, map, ast } transformFileSync(filename, options); // => { code, map, ast } transformFromAstSync

总结

babel 编译的三个阶段以及每个阶段对应的API

stage名称释义相关的API核心的点
stage1parse转成AST语法树@babel/parser词法分析(分词)、语法分析(组装AST)
stage2transform遍历AST,调用transform的各种API进行增删改查@babel/traverse 、@babel/template、@babel/typespath、scope、visitor
stage3generate生成sourcemap@babel/code-frame、@babel/generategenerator、sourcemap

整体能通过@babel/core完成编译的流程

以上提到的api都是tooling packages, 这里再提一下 babel 还有Integration Packages

Integration Packages

@babel/cli

@babel/polyfill

@babel/plugin-transform-runtime

@babel/register

@babel/standalone