在前端培训学习中每个编程语言都有本人的AST,理解AST并能进行一些开发,会给咱们的我的项目开发提供很大的便当。上面就带大家一探到底:
通过本文能理解到什么

  1. JS AST构造和属性
  2. babel插件开发

JS AST简介
AST也就是形象语法树。简略来说就是把程序用树状模式展示。
每种语言(HTML,CSS,JS等)都有本人的AST,而且还有多种AST解析器。
回归JS自身,常见的AST解析器有:
• acorn
• @babel/parser
• Typescript
• Uglify-js
• 等等

不同解析器解析进去的AST有些许差别,但实质上是一样的。
本文将基于@babel/parser来进行示例和解说
上面来看一句常见的代码
import ajax from 'axios'转换后的AST构造如下:
{

    "type": "ImportDeclaration",    "start": 0,    "end": 24,    "loc": {      "start": {        "line": 1,        "column": 0      },      "end": {        "line": 1,        "column": 24      }    },    "specifiers": [      {        "type": "ImportDefaultSpecifier",        "start": 7,        "end": 11,        "loc": {          "start": {            "line": 1,            "column": 7          },          "end": {            "line": 1,            "column": 11          }        },        "local": {          "type": "Identifier",          "start": 7,          "end": 11,          "loc": {            "start": {              "line": 1,              "column": 7            },            "end": {              "line": 1,              "column": 11            },            "identifierName": "ajax"          },          "name": "ajax"        }      }    ],    "importKind": "value",    "source": {      "type": "StringLiteral",      "start": 17,      "end": 24,      "loc": {        "start": {          "line": 1,          "column": 17        },        "end": {          "line": 1,          "column": 24        }      },      "extra": {        "rawValue": "axios",        "raw": "'axios'"      },      "value": "axios"    }  }内容是不是比设想的多?莫慌,咱们一点一点看。

来一张简略图:

ImportDeclaration
语句的类型,表明是一个import的申明。
常见的有:

  • VariableDeclaration:var x = 'init'
  • FunctionDeclaration:function func(){}
  • ExportNamedDeclaration:export function exp(){}
  • IfStatement:if(1>0){}
  • WhileStatement:while(true){}
  • ForStatement:for(;;){}
  • 不一一列举
    既然是一个引入表达式,天然分左右两局部,右边的是specifiers,左边的是source
    specifiers
    specifiers节点会有一个列表来保留specifier
    如果右边只申明了一个变量,那么会给一个ImportDefaultSpecifier
    如果右边是多个申明,就会是一个ImportSpecifier列表
    什么叫右边有多个申明?看上面的示例
    import {a,b,c} from 'x'变量的申明要放弃唯一性
    而Identifier就是鼓捣这个事件的
    source
    source蕴含一个字符串节点StringLiteral,对应了援用资源所在位置。示例中就是axios
    AST是如何转换进去的呢?
    以babel为例子:
    const parser = require('@babel/parser')
    let codeString = `
    import ajax from 'axios'
    `;

let file = parser.parse(codeString,{

sourceType: "module"

})
console.dir(file.program.body)在node里执行一下,就能打印出AST
通过这个小示例,大家应该对AST有个初步的理解,上面咱们谈谈理解它有什么意义
利用场景以及实战
实际上,咱们在我的项目中,AST技术随处可见
• Babel对es6语法的转换
• Webpack对依赖的收集
• Uglify-js对代码的压缩
• 组件库的按需加载babel-plugin
• 等等

为了更好的了解AST,咱们定义一个场景,而后实战一下。
场景:把import转换成require,相似于babel的转换
指标:通过AST转换,把语句
import ajax from 'axios'转为
var ajax = require('axios')要达到这个成果,首先咱们要写一个babel-plugin。先上代码
babelPlugin.js代码如下:
const t = require('@babel/types');

module.exports = function babelPlugin(babel) {

function RequireTranslator(path){

var node = path.nodevar specifiers = node.specifiers//获取变量名称var varName = specifiers[0].local.name;//获取资源地址var source = t.StringLiteral(path.node.source.value)var local = t.identifier(varName)var callee = t.identifier('require')var varExpression = t.callExpression(callee,[source])var declarator = t.variableDeclarator(local, varExpression)//创立新节点var newNode = t.variableDeclaration("var", [declarator])//节点替换path.replaceWith(newNode)

}

return {

visitor: {  ImportDeclaration(path) {    RequireTranslator.call(this,path)        }}

};
};测试代码:
const babel = require('@babel/core');
const babelPlugin = require('./babelPlugin')

let codeString = `
import ajax from 'axios'
`;
const plugins = [babelPlugin]
const {code} = babel.transform(codeString,{plugins:plugins});
console.dir(code)输入后果:
'var ajax = require("axios");
babel-plugin
在babel的官网有开发文档,这里只是简略的形容一下留神要点:
• 插件要求返回一个visitor对象。
• 能够拦挡所有的节点,函数名称就是节点类型,入参是path,能够通过path.node来获取以后节点
• @babel/types提供了大量节点操作的API,同样能够在官网看的具体的阐明

transform
这里的代码大家是不是看着很相熟。没错,就是.babelrc里的配置。咱们开发的插件,配置到.babelrc的plugins里,就能够全局运行了。
作者:cd2001cjm