深入webpack之babel 与 AST

babel的原理

  • parse:把代码code变成AST
  • traverse:遍历AST进行修改
  • generate:把AST变成代码code2
    即 code -> ast -> ast2 -> code2

示例:手动把let变成var

import { parse } from "@babel/parser" // 把代码`code`变成`AST`
import traverse from "@babel/traverse" // 遍历AST
import generate from "@babel/generator" // 把`AST`变成代码`code2`

const code = `let a = 'let'; let b = 2`
const ast = parse(code, { sourceType: 'module' })
traverse(ast, {
  enter: item => {
    if(item.node.type === 'VariableDeclaration'){
      if(item.node.kind === 'let'){
        item.node.kind = 'var'
      }
    }
  }
})
const result = generate(ast, {}, code)
console.log(result.code)

在Chrome运行TS代码:node -r ts-node/register --inspect-brk xxx.ts

先打印看看ast是什么:

AST对象

从ast对象的属性中,可以看到这个program就是上面code这段代码的程序,程序的body里有两个节点:

// const code = `let a = 'let'; let b = 2`
let a = 'let' // 节点1
let b = 2 // 节点2

再看一下这些节点都包含哪些属性,重点关注这三个属性

...
// 声明的节点信息
declarations: [Node]
// 变量声明的关键字是let
kind: "let"
// 类型,说明是一个变量声明
type: "VariableDeclaration"
...

// declarations是一个节点数组,因为可以同时声明多个节点
// let a = 'let'
// name为a的标识符,对应初始值value是'let',类型是字符串
declarations: [
    0: Node
        {
            id: {
                ...,
                name: "a",
                type: "Identifier"
            },
            init: {
                ...,
                value: "let",
                type: "StringLiteral"
            }
    },
    length: 1
]

所以说AST就是用来将源代码字符串,表示成一个树形结构

// traverse用来遍历AST,可以对AST进行修改
traverse(ast, {
// 每进入一个节点,就执行item=>{}函数
  enter: item => {
    ...
  }
})

这样看来,将let变成var就水到渠成了

traverse(ast, {
  enter: item => {
    if(item.node.type === 'VariableDeclaration'){ // 如果是变量声明
      if(item.node.kind === 'let'){ // 如果是let声明
        item.node.kind = 'var' // 将let改成var
      }
    }
  }
})

再使用generate函数将新的AST翻译成code

const result = generate(ast, {}, code) // 传入修改后的ast,还有原始code
console.log(result.code) // 得到新的code

运行后就得到了

var a = 'let';
var b = 2;

为什么要用AST

  • 你很难用正则表达式去替换,正则很容易把let a = 'let'变成var a = 'var'
  • 你需要识别每个单词的意思,才能做到只修改用于变量声明的let
  • 而AST能明确告诉你每个let的意思

下篇《如何将代码转为ES5》

你可能感兴趣的:(深入webpack之babel 与 AST)