当前位置:首页 > 前端 > JavaScript > 正文内容

babel、vue编译,Prettier原理等离不开的AST技术

放牧的风3年前 (2021-11-22)JavaScript6838

概要

本文将通过以下几个方面对AST进行学习

  1. 为什么要了解AST,简要说明AST在开发中的重要性

  2. 什么是AST,对AST有一个直观的认识

  3. AST是如何生成的,分析将代码解析成AST的原理

  4. AST的具体应用,通过解读babel原理、vue模板编译过程,Prettier实现原理,来分析AST在开发中的具体使用。

  5. AST还能做什么,结合工作,思考AST能为我们做些什么

为什么要学习AST

AST(抽象语法树)在开发过程中扮演一个非常重要的角色,但是我们却很少去直接接触它。

无论是代码编译(babel),打包(webpack),代码压缩,css预处理,代码校验(eslint),代码美化(pretiier),Vue中对template的编译,这些的实现都离不开AST。

了解学习AST,能够帮助我们更好的对上面说的这些工具原理进行理解,同时,我们可以利用它去开发一些工具,来优化我们的开发流程,提高开发效率。

什么是AST

AST是对源代码的抽象语法结构的树状表现形式。

在不同的场景下,会有不同的解析器将源码解析成抽象语法树。

下面直观的看一下AST是什么样的

代码如下

let answer = 2 * 3;

对应的AST语法树

{
    "type": "Program",
    "body": [
        {
            "type": "VariableDeclaration",
            "declarations": [
                {
                    "type": "VariableDeclarator",
                    "id": {
                        "type": "Identifier",
                        "name": "answer"
                    },
                    "init": {
                        "type": "BinaryExpression",
                        "operator": "*",
                        "left": {
                            "type": "Literal",
                            "value": 2,
                            "raw": "2"
                        },
                        "right": {
                            "type": "Literal",
                            "value": 3,
                            "raw": "3"
                        }
                    }
                }
            ],
            "kind": "let"
        }
    ],
    "sourceType": "script"
}

那么AST是如何生成的呢?

AST是如何生成的

AST是通过JS Parser (解析器),将js源码转化为抽象语法树,主要分为两步

1. 分词

将整个的代码字符串,分割成语法单元数组(token)。 JS中的语法单元(token)指标识符(function,return),运算符,括号,数字,字符串等能解析的最小单元。主要有以下几种:

  1. 标识符
    没有被引号括起来的连续字符,可以包含字母、数字、_、$,其中数字不能作为开头。
    标识符可能是var,return,function等关键字,也可能是true,false这样的内置常量,或是一个变量。具体是哪种语义,分词阶段不区分,只要正确拆分即可。

  2. 数字 十六进制,十进制,八进制以及科学表达式等都是最小单元

  3. 运算符: +、-、 *、/ 等

  4. 字符串 对计算机而言,字符串只会参与计算和展示,具体里面细分没必要分析

  5. 注释  不管是行注释还是块注释,对于计算机来说并不关心其内容,所以可以作为不可再拆分的最小单元

  6. 空格 连续的空格,换行,缩进等,只要不在字符串中都没有实际的逻辑意义,所以连续的空格可以作为一个语法单元。

  7. 其他,大括号,中括号,小括号,冒号 等等。

依然拿上面的代码作为例子,分词后生成的语法单元数组如下

[
    {
        "type": "Keyword",
        "value": "var",
        "range": [
            0,
            3
        ]
    },
    {
        "type": "Identifier",
        "value": "answer",
        "range": [
            4,
            10
        ]
    },
    {
        "type": "Punctuator",
        "value": "=",
        "range": [
            11,
            12
        ]
    },
    {
        "type": "Numeric",
        "value": "2",
        "range": [
            13,
            14
        ]
    },
    {
        "type": "Punctuator",
        "value": "*",
        "range": [
            15,
            16
        ]
    },
    {
        "type": "Numeric",
        "value": "3",
        "range": [
            17,
            18
        ]
    },
    {
        "type": "Punctuator",
        "value": ";",
        "range": [
            18,
            19
        ]
    }
]

2. 语义分析

语义分析的目的是将分词得到的语法单元进行一个整体的组合,分析确定语法单元之间的关系。

简单来说,语义分析可以理解成对语句(statement)和表达式(expression)的识别。

  1. 语句,一个具备边界的代码区域。相邻的两个语句之间从语法上讲互不影响。比如: var a = 1; if(xxx){xxx}

  2. 表达式,指最终会有一个结果的一小段代码,它可以嵌入到另一个表达式中,且包含在表达式中。比如:a++i > 0 && i< 6

语义分析是一个递归的过程,它会将分词分析出来的数组转化成树形的表达形式。同时,会验证语法,语法如果存在错误的话,会抛出语法错误。

AST的具体应用

文章一开始就说到了,babel,webpack,css预处理,eslint等都应用到了AST树,那么AST到底做了一个什么样的角色呢!? 下面我们就来看一下。

首先看一下babel工作原理的实现。

babel实现原理

babel是一个javascript编译器,用来将es6语法编译成es5

babel的工作可以分为3个阶段:

p1-jj.byteimg.com_tos-cn-i-t2oaga2asx_gold-user-assets_2019_12_12_16efabb5dd074189_tplv-t2oaga2asx-watermark.awebp.png

第1步 解析(Parse)

通过解析器babylon将代码解析成抽象语法树

第2步 转换(TransForm)
通过babel-traverse plugin对抽象语法树进行深度优先遍历,遇到需要转换的,就直接在AST对象上对节点进行添加、更新及移除操作,比如遇到箭头函数,就转换成普通函数,最后得到新的AST树。

第3步 生成(Generate)
通过babel-generator将AST树生成es5代码

vue模板编译过程

Vue 提供了 2 个版本,一个是 Runtime + Compiler ,另一个是 Runtime only 的,前者是包含编译代码的,会把编译的过程放在运行时做,后者是不包含编译代码的,需要借助 webpack 的vue-loader把模板编译render函数。不管使用哪个版本,都有一个环节,就是将模板编译成render函数。

下面我们分析下vue模板的编译过程,这也是vue源码实现中非常重要的一个模块。 vue模板的编译过程分为3个阶段

p1-jj.byteimg.com_tos-cn-i-t2oaga2asx_gold-user-assets_2019_12_12_16efabbb717ce350_tplv-t2oaga2asx-watermark.awebp.png

第1步 解析(Parse)

const ast = parse(template.trim(), options)

将模板字符串解析生成 AST,这里的解析器是vue自己实现的,解析过程中会使用正则表达式对模板顺序解析,当解析到开始标签、闭合标签、文本的时候都会有相对应的回调函数执行,来达到构造 AST 树的目的。

生成的AST 元素节点总共有 3 种类型,1 为普通元素, 2 为表达式,3为纯文本。下面看一个例子

<ul :class="bindCls" class="list" v-if="isShow">
    <li v-for="(item,index) in data" @click="clickItem(index)">{{item}}:{{index}}</li>
</ul>

上面模板解析生成的AST树如下:

ast = {
  'type': 1,
  'tag': 'ul',
  'attrsList': [],
  'attrsMap': {
    ':class': 'bindCls',
    'class': 'list',
    'v-if': 'isShow'
  },
  'if': 'isShow',
  'ifConditions': [{
    'exp': 'isShow',
    'block': // ul ast element
  }],
  'parent': undefined,
  'plain': false,
  'staticClass': 'list',
  'classBinding': 'bindCls',
  'children': [{
    'type': 1,
    'tag': 'li',
    'attrsList': [{
      'name': '@click',
      'value': 'clickItem(index)'
    }],
    'attrsMap': {
      '@click': 'clickItem(index)',
      'v-for': '(item,index) in data'
     },
    'parent': // ul ast element
    'plain': false,
    'events': {
      'click': {
        'value': 'clickItem(index)'
      }
    },
    'hasBindings': true,
    'for': 'data',
    'alias': 'item',
    'iterator1': 'index',
    'children': [
      'type': 2,
      'expression': '_s(item)+":"+_s(index)'
      'text': '{{item}}:{{index}}',
      'tokens': [
        {'@binding':'item'},
        ':',
        {'@binding':'index'}
      ]
    ]
  }]
}

第2步 优化语法树(Optimize)

optimize(ast, options)

vue模板中并不是所有数据都是响应式的,有很多数据是首次渲染后就永远不会变化的,那么这部分数据生成的 DOM 也不会变化,我们可以在patch的过程跳过对他们的比对。
此阶段会深度遍历生成的 AST树,检测它的每一颗子树是不是静态节点,如果是静态节点则它们生成 DOM 永远不需要改变,这对运行时对模板的更新起到极大的优化作用。

遍历过程中,会对整个 AST 树中的每一个 AST 元素节点标记static和staticRoot(递归该节点的所有children,一旦子节点有不是static的情况,则为false,否则为true)。

经过该阶段,上面例子中的ast会变成

ast = {
  'type': 1,
  'tag': 'ul',
  'attrsList': [],
  'attrsMap': {
    ':class': 'bindCls',
    'class': 'list',
    'v-if': 'isShow'
  },
  'if': 'isShow',
  'ifConditions': [{
    'exp': 'isShow',
    'block': // ul ast element
  }],
  'parent': undefined,
  'plain': false,
  'staticClass': 'list',
  'classBinding': 'bindCls',
  'static': false,
  'staticRoot': false,
  'children': [{
    'type': 1,
    'tag': 'li',
    'attrsList': [{
      'name': '@click',
      'value': 'clickItem(index)'
    }],
    'attrsMap': {
      '@click': 'clickItem(index)',
      'v-for': '(item,index) in data'
     },
    'parent': // ul ast element
    'plain': false,
    'events': {
      'click': {
        'value': 'clickItem(index)'
      }
    },
    'hasBindings': true,
    'for': 'data',
    'alias': 'item',
    'iterator1': 'index',
    'static': false,
    'staticRoot': false,
    'children': [
      'type': 2,
      'expression': '_s(item)+":"+_s(index)'
      'text': '{{item}}:{{index}}',
      'tokens': [
        {'@binding':'item'},
        ':',
        {'@binding':'index'}
      ],
      'static': false
    ]
  }]
}

第3步 生成代码

const code = generate(ast, options)

通过generate方法,将ast生成render函数

with(this){
  return (isShow) ?
    _c('ul', {
        staticClass: "list",
        class: bindCls
      },
      _l((data), function(item, index) {
        return _c('li', {
          on: {
            "click": function($event) {
              clickItem(index)
            }
          }
        },
        [_v(_s(item) + ":" + _s(index))])
      })
    ) : _e()
}

Prettier实现原理

通过上面对babel实现原理和vue模板的编译原理可以看出,他们的实现有很多相同之处,都是先将源码解析成AST树,然后对AST树就行处理,最后生成想要的东西。

Prettier的实现同样是这样,首先依然是将代码解析生成AST树,然后是对AST遍历,调整长句,整理空格,括号等,最后输出代码,这里就不赘述了。

小结

我们分析了Babel原理、vue模板编译过程、Prettier原理,这里我们简单总结一下。
如果把源码比作一个机器,那么分词过程就是将这台机器拆分成一个个零件,语义分析过程就是分析每个零件的位置以及作用,然后根据需要对零件进行加工处理,最后再组装成一个新的机器。

AST还能做什么

那么工作中我们能使用AST做些什么呢?!

这里就要发挥想象了,看看我们日常工作中有什么需求是可以通过AST开发个工具来解决。
比如,可以通过AST可以将代码自动转成流程图;
或者根据自定义的注释规范,通过工具自动生成文档;
或是通过工具自动生成骨架屏文件。



原文链接:https://juejin.cn/post/6844904019505184776


扫描二维码推送至手机访问。

版权声明:本文由放牧的风发布,如需转载请注明出处。

本文链接:https://grazingwind.com/post/78.html

分享给朋友:
返回列表

上一篇:JavaScript中undefined与null的区别

没有最新的文章了...

相关文章

ES6必知必会 —— Module

ES6必知必会 —— Module

1. ES6在语言标准的层面上,实现了模块功能,成为浏览器和服务器通用的模块解决方案,完全可以取代 CommonJS 和 AMD 规范,基本特点如下:每一个模块只加载一次, 每一个JS只执行一次, 如果下次再去加载同目录下同文件,直接从内存...

JavaScript专题系列目录

JavaScript专题系列目录

JavaScript专题之跟着underscore学防抖JavaScript专题之跟着underscore学节流JavaScript专题之数组去重JavaScript专题之类型判断(上)JavaScript专题之类型判断(下)JavaScr...

JavaScript ES6 系列目录

JavaScript ES6 系列目录

ES6 系列之 let 和 constES6 系列之模板字符串ES6 系列之箭头函数ES6 系列之模拟实现 Symbol 类型ES6 系列之迭代器与 for ofES6 系列之模拟实现一个 Set 数据结构ES6 系列之 WeakMapES...

JavaScript 中常见设计模式整理

JavaScript 中常见设计模式整理

开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式。本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知。JavaScript 中常见设计模式单例模式策略模式代理模式迭代器模式发布-...

二叉树及其遍历方法:JavaScript实践

二叉树及其遍历方法:JavaScript实践

二叉树常见的数组,栈,列表都是线性结构常见的树型结构有:文件夹目录,dom结构,路由的配置...二叉树二叉树是每个结点最多有两个子树的树形结构,每个结点的度最多是2。左边的称为 左子树 , 右边的称为 右子树 , 左子树 , 右子树 是有顺...

这些原生DOM操作你还记住多少😨

这些原生DOM操作你还记住多少😨

前言 最近在二次封装一个公司内部的UI组件库,其中一个模块就是给 element-plus 的 message 进行扩展,大量运用到了原生DOM操作,操作DOM最方便...

评论列表

游客
14分钟前

这么好的帖子,应该加精华!http://www.dnf70.com/358.html

游客
20分钟前

论坛的人气不行了!http://www.mj-life.cn/265078.html

游客
45分钟前

楼主英明!http://www.indaseg.com/a/a/2292.html

游客
57分钟前

精华帖的节奏啊!http://e43me6.impactmv.com

游客
1小时前

终于看完了,很不错!http://www.indaseg.com/a/a/5041.html

游客
2小时前

有机会找楼主好好聊聊!http://t976l.djraj.net

游客
2小时前

看在楼主的面子上,认真回帖!http://www.a5km.com/yxgl/jdqs/27902.html

游客
2小时前

这个帖子好无聊啊!http://s8akd2.bmw8294.com

游客
2小时前

今天过得很不爽!http://udwh.https://www.weimaitu.com/

游客
2小时前

文章写太挺好了,真的值得推荐http://rvq.onejhac.com

游客
2小时前

祖国尚未统一,我却天天灌水,好内疚!https://www.uuu9923.cn/2258.html

游客
2小时前

哥回复的不是帖子,是寂寞!https://www.ggplus.cn/25582.html

游客
2小时前

楼上的很有激情啊!http://www.dnf70.com/1642.html

游客
2小时前

楼主说的我也略懂!http://www.dnf70.com/358.html

游客
2小时前

楼主的帖子提神醒脑啊!http://www.a5km.com/yxgl/jdqs/28016.html

游客
3小时前

楼上的很有激情啊!http://www.indaseg.com/a/a/3158.html

游客
3小时前

投楼主一票,不用谢哦!http://j80jg.96h.cc/11/5.html

游客
3小时前

读了楼主的帖子,顿时马桶就通了。。。http://www.a5km.com/yxgl/jdqs/27371.html

游客
3小时前

语言表达流畅,没有冗余,读起来很舒服。http://6uzgd.jinzhaogebinwang.com

游客
3小时前

青春不在了,青春痘还在!http://www.a5km.com/yxgl/jdqs/27231.html

游客
3小时前

楼主很有艺术范!http://www.a5km.com/yxgl/jdqs/28238.html

游客
3小时前

看在楼主的面子上,认真回帖!http://p289i.cv-works.com

游客
3小时前

管它三七二十一!http://www.hcs3.com

游客
4小时前

经典,收藏了!http://www.dnf70.com/2795.html

游客
4小时前

顶顶更健康!http://www.indaseg.com/a/a/2103.html

游客
4小时前

吹牛的人越来越多了!https://m.pc235.com/game/980.html

游客
4小时前

顶一个!http://www.a5km.com/yxgl/jdqs/29289.html

游客
4小时前

怎么我回帖都没人理我呢?http://www.a5km.com/yxgl/dnf/26928.html

游客
4小时前

很有品味!https://www.sjzsaisi.com/post/15060.html

游客
4小时前

顶!顶!顶!http://www.a5km.com/yxgl/jdqs/29089.html

游客
4小时前

最近回了很多帖子,都没人理我!http://cix4l.osgoodeyoga.com

游客
4小时前

林子大了,什么鸟都有了啊!https://www.ggplus.cn/19142.html

游客
4小时前

楼主的帖子提神醒脑啊!http://jzc.962898.com

游客
4小时前

好东西,学习学习!http://ebmef.qw1m.com/21/3.html

游客
4小时前

楼主的头像是本人吗?http://kxgyc.salasal.com

游客
4小时前

楼主是一个神奇的青年!http://0w9iqs.pixelnate.com

游客
4小时前

楼主看起来很有学问!http://www.a5km.com/yxgl/jdqs/29122.html

游客
4小时前

楼主人气很旺!http://0kk.salasal.com

游客
5小时前

论坛人气好旺!http://www.a5km.com/yxgl/dnf/24796.html

游客
5小时前

读了楼主的帖子,顿时马桶就通了。。。http://chaomofang.cn/news/23c099283.html

游客
5小时前

看帖不回帖都是耍流氓!http://www.a5km.com/yxgl/jdqs/28488.html

游客
5小时前

我默默的回帖,从不声张!http://www.a5km.com/yxgl/jdqs/27231.html

游客
6小时前

楼上的很有激情啊!http://98z92.xhysg-eye.com/W/3.html

游客
6小时前

一口气看完了,我要下去回味回味了!http://gcv9f.novodance.com

游客
6小时前

楼主好聪明啊!http://www.a5km.com/yxgl/jdqs/28061.html

游客
6小时前

鸟大了,什么林子都敢进啊!http://www.zjlytx.com

游客
7小时前

顶一个!http://cq.3f2s.com/wanjiaxinde/

游客
7小时前

楼主是男的还是女的?http://www.dnf70.com/1569.html

游客
7小时前

论坛人气好旺!http://6pj.mean-girl.com

游客
7小时前

收藏了,以后可能会用到!http://www.dnf70.com/495.html

游客
7小时前

在哪里跌倒,就在那里多爬一会儿!http://www.indaseg.com/a/a/1777.html

游客
8小时前

好东西,赞一个!http://oi67c.menel.net

游客
8小时前

楼主的头像是本人吗?http://axh9b.jianglichanpin.com/h/3.html

游客
8小时前

无图无真相!http://www.a5km.com/yxgl/jdqs/28016.html

游客
8小时前

有内涵!http://5lvl.toroferrer.com

游客
8小时前

楼主主机很热情啊!http://s3uinn.wwires.com

游客
8小时前

文章写太挺好了,真的值得推荐https://www.uuu9923.cn/1313.html

游客
8小时前

经典,收藏了!http://www.a5km.com/yxgl/jdqs/28166.html

游客
8小时前

怪事年年有,今年特别多!http://b7t.jdrama.net

游客
8小时前

不错哦,楼主这是要火的节奏啊!http://www.a5km.com/yxgl/dnf/22341.html

游客
8小时前

青春不在了,青春痘还在!http://www.dnf70.com/1569.html

游客
8小时前

以后就跟楼主混了!http://www.a5km.com/yxgl/jdqs/29256.html

游客
8小时前

楼上的说的很多!http://wlic6q.fanmcreole.com

游客
9小时前

看了这么多帖子,第一次看到这么高质量内容!http://ltj8.readyveg.net

游客
9小时前

很有看点!http://evr.trascomp.com

游客
9小时前

大神好强大!http://www.a5km.com/yxgl/dnf/22505.html

游客
9小时前

赞一个!http://www.indaseg.com/a/a/4900.html

游客
9小时前

信楼主,考试不挂科!http://4znivw.salasal.com

游客
9小时前

关注一下!http://www.a5km.com/yxgl/jdqs/28991.html

游客
9小时前

哥回复的不是帖子,是寂寞!http://www.a5km.com/yxgl/jdqs/26603.html

游客
9小时前

论坛的帖子越来越有深度了!http://vsp5mc.teqempire.com

游客
9小时前

楼主是一个神奇的青年!http://www.a5km.com/yxgl/dnf/25651.html

游客
10小时前

这一年啥事没干,光研究楼主的帖子了!http://www.a5km.com/yxgl/jdqs/28255.html

游客
11小时前

吹牛的人越来越多了!http://www.hmy360.com

游客
11小时前

每天顶顶贴,一身轻松啊!http://3894.onejhac.com

游客
11小时前

很有品味!http://www.a5km.com/wzjc/dnfkm/26044.html

游客
11小时前

经典,收藏了!http://www.a5km.com/wzjc/jdqskm/25916.html

游客
11小时前

信楼主,得永生!http://www.a5km.com/yxgl/dnf/23795.html

游客
12小时前

感觉不错!https://www.sjzsaisi.com/post/14944.html

游客
12小时前

不灌水就活不下去了啊!http://ygxz.901908.com

游客
12小时前

最近回了很多帖子,都没人理我!http://www.dnf70.com/592.html

游客
12小时前

楼主是一个典型的文艺青年啊!http://qtfg.menel.net

游客
12小时前

在哪里跌倒,就在那里多爬一会儿!http://www.a5km.com/yxgl/jdqs/27489.html

游客
12小时前

很经典,收藏了!http://www.dnf70.com/3105.html

游客
12小时前

坚持回帖!https://www.ggplus.cn/30252.html

游客
13小时前

顶一个!http://www.dnf70.com/1172.html

游客
13小时前

精华帖的节奏啊!http://www.a5km.com/yxgl/dnf/26900.html

游客
13小时前

楼主加油,看好你哦!http://www.almosthomeanimalrescue.com

游客
13小时前

今天的心情很不错啊http://rsuyds.osgoodeyoga.com

游客
13小时前

最近回了很多帖子,都没人理我!http://q8yd.962898.com

游客
14小时前

顶顶更健康!http://www.a5km.com/yxgl/dnf/25738.html

游客
14小时前

鉴定完毕!http://ksdj2.salasal.com

游客
14小时前

大神就是大神,这么经典!http://cq.3f2s.com/wanjiaxinde/

游客
14小时前

知识就是力量啊!http://www.dnf70.com/2522.html

游客
14小时前

我只看看不说话。。。http://p358v.bzjhfzzhzs.com

游客
14小时前

这一年啥事没干,光研究楼主的帖子了!http://www.a5km.com/yxgl/jdqs/29039.html

游客
14小时前

看帖不回帖的人就是耍流氓,我回复了!https://www.hncloud.com/

游客
14小时前

我对楼主的敬仰犹如滔滔江水绵延不绝!http://www.a5km.com/yxgl/jdqs/27030.html

游客
14小时前

最近压力山大啊!http://6es3.dvxatope.com

游客
14小时前

楼主很有经验啊!http://www.a5km.com/yxgl/jdqs/28601.html

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。