使用Babel来编写一个插件一

Babel 是一个可以用于代码转换的工具,可以将一些新特性的代码,转换成兼容低版本浏览器的代码。
我们来实现删除掉写在方法中的console
在开发过程中,我们做调试的时候,会用console在控制台输出信息,那么在生产环境的时候,就要清除掉这些输出,那么我们现在就来实现这样的一个插件

注:笔者目前使用的是babel版本是7

  • 开始:首先项目中引用babel提供的一些工具包

    npm install --save-dev @babel/parser @babel/generator @babel/traverse @babel/types
    

现在介绍一下这些工具包的作用:
@babel/parser:是用于将编写的代码转换成抽象语法树(AST)结构的代码
@babel/generator:是用于将转换后的抽象语法树(AST)转换为 JavaScript 字符串。
@babel/traverse:是可以浏览、分析和修改抽象语法树(AST),我们主要也是利用这个模块来这次的需求
@babel/types:是提供的一系列的类型,可以用这个包来比对AST的类型
先创建一个用于测试的test.js

console.log('log----1-1')
console.info('info-----1-2')
console.error('error-----1-3')

function foo2() {
	console.log('log----2-1')
	console.info('info-----2-2')
	console.error('error-----2-3')
}

const foo3 = () => {
	console.log('log----3-1')
	console.info('info-----3-2')
	console.error('error-----3-3')
}

;(function () {
	console.log('log----4-1')
	console.info('info-----4-2')
	console.error('error-----4-3')
})()

$(function () {
	console.log('log----5-1')
	console.info('info-----5-2')
	console.error('error-----5-3')
})

const foo6 = {
	fun1: function () {
		console.log('log----6-1')
		console.info('info-----6-2')
		console.error('error-----6-3')
	},
}

const fun = function () {}
fun.prototype.test = function () {
	console.log('log----7-1')
	console.info('info-----7-2')
	console.error('error-----7-3')
}

接着在新建一个index.js

// ast 格式化网站   https://astexplorer.net/
// https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md babel中文文档
const parser = require('@babel/parser')
const traverse = require('@babel/traverse')
const generator = require('@babel/generator')
const types = require('@babel/types')
//node fs 模块,读取文件信息
const fs = require('fs')
//删除console的哪些方法
const reg = /(log|error)$/
//是否删除所有的console,包括方法外面的,如果是false只删除方法里面的
const isRemoveAllConsole = true

//读取刚刚创建的test.js
let testFileContent = fs.readFileSync('./test.js', 'utf-8')
const code = testFileContent
//1,先将代码转换成ast
const codeAst = parser.parse(code)
//2.1创建一个访问者对象,把这个理解为,需要访问这个语法树中的哪些类型
let visitors = {
	// 如果是调用表达式
	CallExpression(path) {
		// 取出调用的节点信息
		const { callee } = path.node
		//判断是不是调用节点信息,并且是对象的名称是console,方法符合正则的判断
		if (
			types.isMemberExpression(callee) &&
			callee.object.name === 'console' &&
			reg.test(callee.property.name)
		) {
			if (isRemoveAllConsole) {
                                // 删除掉这个节点
				path.remove()
			} else {
				// 向上找,如果找到父元素是方法,就删除
				let parentFun = path.findParent((path) => {
					return (
						// 如果是函数声明
						path.isFunctionDeclaration() ||
						// 如果是箭头函数表达式
						path.isArrowFunctionExpression() ||
						// 如果是函数表达式
						path.isFunctionExpression()
					)
				})
				if (parentFun) {
					path.remove()
				}
			}
		}
	},
}


//2,分析修改AST,第一个参数是AST,第二个参数是访问者对象
traverse.default(codeAst, visitors)

//3,生成新的代码,第一个参数是AST,第二个是一些可选项,第三个参数是原始的code
let newCode = generator.default(codeAst, {}, code)
//会返回一个对象,code就是生成后的新代码
// 调用code,生成一个新的js文件
fs.writeFileSync('./newTest.js', newCode.code)

然后再控制台运行
node index.js
然后就去看看效果吧!

posted @ 2020-12-31 14:42  dwbo  阅读(148)  评论(0)    收藏  举报