手写babel插件-第二讲

这是手写babel系列的第二讲。这一讲我们来说说抽象语法树(AST)。今天是2024年 大年初一,在这里先祝大家新年快乐,龙年行大运。

AST是干啥的?

它是我们源代码的一种抽象表示。更具体的来说就是使用树状结构去表示代码的语法结构

AST是如何生成的?

它的形成可以分为3个步骤,分别是 词法分析语法分析语义分析

这里有一个问题,大家需要了解这方面的知识吗?我们拿到AST去做一些事情,可以利用AST可视化网站,这很方便的,比如下面这样:

我觉着是一定要了解的。功利性的来讲,如果你在面试过程中遇到了相关的问题,而如果你把AST可视化网站搬过去应付面试官的话,那大概率这个知识点你是不通过,虽然利用AST网站去做源代码转换的事情 这是一个事实。

词法分析

这个过程主要就是读取代码,将代码都拆解成一个一个的最小单元(有人管它叫tokens,也有人管它叫做单词,叫啥不重要,能够知道它是AST的最小组成单元即可)。

语法分析

在词法分析的基础上,根据语言的语法规则,分析程序基本语法结构,并将最小单元组成树状结构。

语义分析

这一步主要是用来检查源代码是否存在语法错误,如果有错误的话就直接抛出来。

如何写一个最简单的babel插件

上面这个作为了解就可以了,不必过多深入。接下来我们来看看如何写一个babel插件。

还是一样,先打开AST可视化网站,然后选中transform选项,如下图:

我们看到,左下方,默认就有一个babel插件。左上方是一段js源代码,右上方是源代码对应的AST。左上方的js源代码 经过 左下方的babel插件处理后生成了右下方的目标代码

那我们接下来就一起探讨一下 这个babel插件是如何编写的。

节点(node)

右上方是实时的AST,它里面的每个对象,都可以被叫做一个节点。

这些节点都有以下类似的结构:

javascript 复制代码
{
  type: "XXXXX",
  name: ...,
  id: {...},
  params: [...],
  left: {...},
  right: {...},
  body: {...}
}

上面的这些属性里,type字段是必须要有的,用来标识当前节点的类型。它是一个枚举,包含 XxDeclaration、XxStatement、XxExpression等等。

插件里的babel参数

javascript 复制代码
export default function (babel) {
  const { types: t } = babel;
  
  return {
    name: "ast-transform", // not required
    visitor: {
      Identifier(path) {
        path.node.name = path.node.name.split('').reverse().join('');
      }
    }
  };
}

首先,我们看到,一个babel插件其实就是一个函数,然后,这个函数需要返回一个对象objobj需要拥有一个访问者vistor属性。这个vistor属性的值也是一个对象b对象b由不同的函数属性构成

babel参数其实指代的是 @babel/core 这个核心模块,里面包含了一些工具方法。比如babel.types对象,这个对象里包含了很多的方法,支持你去创建不同类型的节点。比如:babel.types.stringLiteral方法用于创建一个字符串值。

本篇文章里暂时还用不到,后续文章会有讲到。

vistor访问者

它主要是用来处理节点的增删改查的。所以它是很重要的一个概念。我们知道,节点的类型有很多种,你想要处理哪个,就要把这一类的节点类型写在一个函数里去处理。

以我们这里为例子:

javascript 复制代码
let tips = [];

我们要写一个插件,用来将上述代码的 let 改为 const,那我们要怎么写呢?

首先,将我们的代码放到 AST可视化网站上,随后,我们应该有如下思路:

  • let这个关键字,对于AST来说,它也是一个节点。
  • 既然let都是一个节点了,那const也应该是一个节点。
  • 这个需求其实也就是替换节点。
  • 替换节点的代码位置应该在哪里呢?刚才我们讲过,vistor就是干这个事的。
  • 如何写呢?我们刚才也说过,你要把同一个类型的节点处理写在一个函数里。
  • 那我怎么知道let属于哪个类型的节点?AST可视化网站不就派上用场了嘛。你把上面的代码放到这个可视化网站里看一下不就知道啦。
  • 经过查看得知,let 的节点类型 是VariableDeclaration

于是,我们就可以写出下面的babel插件:

javascript 复制代码
export default function (babel) {
  const { types: t } = babel;
  
  return {
    name: "ast-transform", // not required
    visitor: {
      VariableDeclaration(path){
      	path.node.kind = 'const';
      }
    }
  };
}

最后发现,我们如约的完成了这个需求。

最后

好啦,本期babel分享到这里就结束啦,希望我的分享能够对你有帮助,我们下期再见啦~~

相关推荐
爱的叹息7 分钟前
【前端】基于 Promise 的 HTTP 客户端工具Axios 详解
前端·网络·网络协议·http
遗憾随她而去.13 分钟前
从 0 开始认识 WebSocket:前端实时通信的利器!
前端·websocket·网络协议
老兵发新帖1 小时前
pnpm常见报错解决办法
前端
Sonetto19991 小时前
Nginx 反向代理,啥是“反向代理“啊,为啥叫“反向“代理?而不叫“正向”代理?它能干哈?
运维·前端·nginx
沐土Arvin1 小时前
理解npm的工作原理:优化你的项目依赖管理流程
开发语言·前端·javascript·设计模式·npm·node.js
好_快1 小时前
Lodash源码阅读-baseUniq
前端·javascript·源码阅读
不秃的开发媛1 小时前
前端技术Ajax入门
java·开发语言·前端
牧羊狼的狼1 小时前
React.memo 和 useMemo
前端·javascript·react.js
xixixin_1 小时前
【uniapp】vue2 搜索文字高亮显示
java·服务器·前端·uni-app·交互·文字高亮
还是鼠鼠1 小时前
Android移动应用开发入门示例:Activity跳转界面
android·前端·gitee·android studio·android-studio