前端开发之JavaScrpit AST 实战分析

2022-12-23 0 851

每一C词汇都有他们的AST,介绍AST并能展开许多合作开发,会给他们的工程项目合作开发提供更多非常大的便捷。上面就带他们一探到底:

透过责任编辑能介绍到甚么

JS AST内部结构和特性babel应用流程合作开发

JS AST概要

AST也就是抽象化句法树。单纯而言是把流程用抽象化化方式展现出。

五种词汇(HTML,CSS,JS等)都有他们的AST,所以除了多种相同AST解释器。

重回JS这类,常用的AST解释器有:

acorn@babel/parserTypescriptUglify-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”} }

内容是不是比想象的多?莫慌,他们一点一点看。

来一张简略图:

前端开发之JavaScrpit AST 实战分析

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){ functal = 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对象。可以拦截所有的节点,函数名称是节点类

transform

这里的标识符他们是不是看着很熟悉。没错,是.babelrc里的配置。他们合作开发的应用流程,配置到.babelrc的plugins里,就可以全局运行了。

作者:cd2001cjm

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务