19.重学webpack——原理之AST抽象语法树

【重学webpack系列——webpack5.0】

1-15节主要讲webpack的使用,当然,建议结合《webpack学完这些就够了》一起学习。
从本节开始,专攻webpack原理,只有深入原理,才能学到webpack设计的精髓,从而将技术点运用到实际项目中。
可以点击上方专栏订阅哦。

以下是本节正文:


ast语法树(会有专门章节详细介绍AST,本节只是了解大概过程)在我们工作中经常会用到,比如以下场景:

  • 代码语法的检查、代码风格的检查、代码的格式化、代码的高亮、代码错误提示、代码自动补全等等
    • 如 JSLint、JSHint 对代码错误或风格的检查,发现一些潜在的错误
    • IDE 的错误提示、格式化、高亮、自动补全等等
  • 代码混淆压缩
    • UglifyJS2 等
  • 优化变更代码,改变代码结构使达到想要的结构
    • 代码打包工具 webpack、rollup 等等
    • CommonJS、AMD、CMD、UMD 等代码规范之间的转化
    • CoffeeScript、TypeScript、JSX 等转化为原生 Javascript

1.一般需要ast转换的工作流程:

老代码=>老语法树=>遍历语法树上的各个节点=>对语法树进行修改转换=>新的语法树=>根据新的语法树重新生成源代码

  • 举例:es6 => es语法树 => 遍历箭头函数节点 => 把箭头函数转成普通函数 => 重新生成es5代码

19.重学webpack——原理之AST抽象语法树

2.AST抽象语法树解析步骤:

如上图前半部分所示,具体步骤为:

  1. 对源代码进行词法分析

    将语句切成一个个的单词,不关心语法含义,这些单词构成了token数组,被称为token留

  2. 语法分析

    根据token进行语法分析,生成语法树

3.实战举例

function ast(){}转成function newAST(){}

  1. 安装依赖

    npm i esprima estraverse -S

    • esprima:解析器,将源代码转换成抽象语法树
    • estraverse:是一个方法,用来遍历抽象语法树

    npm i escodegen -D

    • escodegen:将转换后的语法树,重新生成源码
  2. 代码

    代码步骤分为:

    1. 将源码转成AST语法树
    2. 遍历语法树,修改语法树节点
    3. 将新的语法树,转成新的源码
    // 把源代码转成AST语法树
    let esprima = require('esprima');
    // 遍历语法树
    let estraverse = require("estraverse");
    // 把转换后的语法树,重新生成源码
    let escodegen = require('escodegen');
    // 一般工作流都是:老代码=>老语法树=>遍历语法树上的各个节点=>对语法树进行修改转换=>新的语法树=>根据新的语法树重新生成源代码
    // 比如:es6 => es语法树 => 遍历箭头函数节点 => 把箭头函数转成普通函数 => 重新生成es5代码
    
    let sourceCode = `function ast(){}`;
    let astTree = esprima.parseModule(sourceCode);
    console.log(astTree);
    console.log("在线解析AST,可以登录网址:https://astexplorer.net")
    
    let indent = 0; // 缩进,计算缩进的空格数,打印的时候看起来更加清晰点
    const padding = () => " ".repeat(indent); // 字符串缩进,打印的时候看起来更加清晰点
    // estraverse遍历语法树,用的是深度优先遍历
    estraverse.traverse(astTree, {
      enter(node){
        console.log(padding() + node.type + '进入');
        if (node.type === 'FunctionDeclaration') {
          node.id.name = 'newAST';// 这是进行语法转换,在这里相当于改了函数的名称
        }
        indent += 2;
      },
      leave(node){
        indent -= 2;
        console.log(padding() + node.type + '离开')
      }
    })
    
    // escodegen重新生成源代码
    let result = escodegen.generate(astTree);
    console.log(result); // function newAST() {}
    
上一篇:可信前端之路:代码保护


下一篇:【译】一个超级小的编译器