babel是个js编译器,写babel插件其实就是操作ast。
我们日常项目中使用ast的场景很多,比如eslint, codemods, css parsers, css in js等等,不同的工具的ast解析规则可能稍有区别,这里以babel的规范为主。

ast介绍

ast的定义如下

An abstract syntax tree is a tree representation of source code written in a programming language. Each node of the tree denotes a construct occurring in the source code.

ast的处理包括三个步骤, parse, transform, generate,我们关注点在前两步,具体要操作的是第二步。

parse

将源码解析成ast分为两步,词法分析和语法分析,以 const a = 5 + 3;为例。

词法分析是将源码字符串拆分成一个个token,我们这里把token简化为

interface Token {type: string,value: string
}

我们例子里的结果就是

语法分析就是将这些token组合成ast

大概如下

{"type": "VariableDeclaration","declarations": [{"type": "VariableDeclarator","id": {"type": "Identifier","name": "a"},"init": {"type": "BinaryExpression","left": {"type": "Literal","value": 5},"operator": "+","right": {"type": "Literal","value": 3}}}],"kind": "const"
}

具体的ast可以在这里查看astexplorer

ast就像一个DOM tree,每个ast的节点是个Node实例,每个Node有以下接口

interface Node {type: string;
}

具体的类型还有其他属性,比如Function

interface Function extends Node {id: Identifier | null;params: [ Pattern ];body: BlockStatement;generator: boolean;async: boolean;
}

Transform

就是遍历ast,然后对节点进行增删改查,这是我们开发babel插件时接入的阶段,后面会具体介绍。

Generate

就是深度优先遍历ast,生成对应的源码即可,同时还可以生成source map.

写插件

babel插件就是一个函数,返回一个带visitor属性的对象,会在遍历ast过程中对指定类型的节点进行操作,其中t表示type,可以用于创建或验证节点等,具体用法可以参考@babel/types,这块参考的这里。

export default function({ types: t }) {return {visitor: {Identifier(path, state) {},}};
};

其中每个节点节点类型对应的回调表示对这个类型节点的操作

path

其中path指的是两个节点的连接,其中可以访问节点信息,也包含相关增删改查方法,类似于DOM操作,其中path上的操作是操作子节点,想操作父节点可以使用path.parentPath

插入相邻节点

FunctionDeclaration(path) {path.insertBefore(t.expressionStatement(t.stringLiteral("Because I'm easy come, easy go.")));path.insertAfter(t.expressionStatement(t.stringLiteral("A little high, little low.")));
}
+ "Because I'm easy come, easy go.";function square(n) {return n * n;}
+ "A little high, little low.";

插入进一个数组类型节点

ClassMethod(path) {path.get('body').unshiftContainer('body', t.expressionStatement(t.stringLiteral('before')));path.get('body').pushContainer('body', t.expressionStatement(t.stringLiteral('after')));
}
 class A {constructor() {
+   "before"var a = 'middle';
+   "after"}}

FunctionDeclaration(path) {path.remove();
}
- function square(n) {
-   return n * n;
- }

BinaryExpression(path) {path.replaceWith(t.binaryExpression("**", path.node.left, t.numberLiteral(2)));
}
 function square(n) {
-   return n * n;
+   return n ** 2;}

可以通过.node获取

BinaryExpression(path) {path.node.left;path.node.right;path.node.operator;
}

也可以.get

BinaryExpression(path) {path.get('left');
}

state

可以用来获取babel配置时的参数

//配置
{plugins: [["my-plugin", {"option1": true,"option2": false}]]
}

结果

export default function({ types: t }) {return {visitor: {FunctionDeclaration(path, state) {console.log(state.opts);// { option1: true, option2: false }}}}
}

例子

上篇文章我们说在使用微前端时,import一个线上模块会造成fast refresh失效,因此我们的解决方式是写一个loader,即实现的功能是将

//a指的是线上模块
import('a')

修改为

//b指的是线下模块
import('b')

关键代码为

 CallExpression(path, state) {if (!Array.isArray(state.opts.modules)) {throw new Error('参数错误')}if (path.node.callee.type === 'Import' &&//modules参数为需要替换的模块state.opts.modules.some((item) => path.node.arguments[0].value === item)) {path.replaceWith(t.CallExpression(t.identifier('import'), [//b为替换成的本地模块t.stringLiteral('b'),]))}},

参考

  • babel-handbook
  • Revealing the magic of AST by writing babel plugins

AST介绍和babel插件开发相关推荐

  1. JavaScript 学习笔记-- ES6学习(一)介绍以及Babel的使用

    本文摘自阮一峰老师的<ECMAScript 6入门>,原文地址:http://es6.ruanyifeng.com/#docs/intro ECMAScript 6 是一个泛指,含义是5. ...

  2. AST反混淆之路——babel基本知识及常用转换操作

    本文章是学习AST反混淆的笔记,包括AST介绍.babel介绍(重点!!!).以及部分AST反混淆实验代码 参照Babel插件开发助手(官方):https://blog.csdn.net/weixin ...

  3. AST基础知识:环境的搭建与babel库的安装

    本文环境为win10系统,兼容各win系统(只需区分32位及64位操作系统),linux环境请自行下载测试. 一.安装nodejs 安装地址: https://nodejs.org/zh-cn/dow ...

  4. idea插件开发(02)---相关概念介绍

    上一篇已经介绍了idea插件开发最简单的一个例子 本篇来说说相关概念,部分概念是网上抄的,网友的不同说法,但大致都是同一个意思 1.idea介绍 idea整个组件结构是基于PicoContainer的 ...

  5. 理解Babel是如何编译JS代码的及理解抽象语法树(AST)

    Babel是如何编译JS代码的及理解抽象语法树(AST) 1. Babel的作用是?    很多浏览器目前还不支持ES6的代码,但是我们可以通过Babel将ES6的代码转译成ES5代码,让所有的浏览器 ...

  6. Babel?No!AST!

    Babel 在我很小的时候,有人告诉我代码要写的有艺术感.我当时内心:......真高级啊,装起来了.但是伴随着时代的变迁,各种提案的通过,js的写法也逐渐升级,语法糖也多了起来,原来的三四行代码,啪 ...

  7. babel import语法 js_Babel 的理解

    由于 markdown 排版问题建议从掘金阅读:https://juejin.cn/post/6902323049513615374 目录 前言 babel 是什么 babel 能做什么 工作流程 解 ...

  8. babel原理_手写webpack核心原理,再也不怕面试官问我webpack原理

    手写webpack核心原理 一.核心打包原理 1.1 打包的主要流程如下 1.2 具体细节 二.基本准备工作 三.获取模块内容 四.分析模块 五.收集依赖 六.ES6转成ES5(AST) 七.递归获取 ...

  9. Babel 学习日记(0)

    作者:商见曜 来源:恒生LIGHT云社区 作为现代前端项目必备的一种技术,Babel 是一个编译器,用于将前沿的 JS 语法转换为浏览器支持的语法.接下来就让我们一起深入学习一下吧. Babel 的介 ...

最新文章

  1. .net解决Xss攻击
  2. Web_audio_spatialization_basics
  3. Iptables Nat转发
  4. 电脑黑屏的原因有哪些
  5. linux修改环境截图,Linux环境下php实现给网站截图的方法.docx
  6. BA无标度网络的仿真实现
  7. war包还原成项目_将War包还原成java web项目
  8. 2021中青杯数学建模B题
  9. MATLAB机器人运动学与动力学(自己学习用)
  10. 一份平面设计指南分享给大家
  11. LZY的CQU水下机器人视觉学习笔记(一)
  12. html如何制作扑克,用css制作扑克牌
  13. 圣诞音乐贺卡beepMusic_v6d;--铃儿响叮当;
  14. 一文告诉你,SIMULIA/Abaqus究竟有多强大
  15. ubuntu默认账户丢失后找回
  16. C3D复现出现的问题及其解决方法
  17. 【原】Java学习笔记025 - 内部类
  18. 深度神经网络TensorFlow基础学习(3)——卷积神经网络的参数个数和张量大小
  19. 关于px/rem/vw 之间的换算关系
  20. 数据基础设施加速数字经济,“河图”引擎推进鲲鹏计算产业

热门文章

  1. python编程源码
  2. Python中IO概述
  3. 用树莓派4b搭建Terraria服务器
  4. 报错 expect ‘:‘ at 0, actual = com.alibaba.fastjson.JSONException: expect ‘:‘ at 0, actual =
  5. java环境变量配置验证,java环境变量配置
  6. 0818骑行仙湖绿道
  7. Vue项目img标签图片加载失败/显示不成功,显示默认图片
  8. Java带GUI求柱体的体积
  9. Mac显示和关闭隐藏文件
  10. php数值变成函数,PHP实现金额数字转换成大写函数