当前位置: 首页 > news >正文

写一个vite插件处理console

写一个vite插件去除代码中的console

使用babel做处理。简单处理,复杂情况未考虑。
学习babel写的demo。

项目根目录新建文件
babel-plugin-remove-console.js
rollup-plugin-remove-console.js

在这里插入图片描述

babel-plugin-remove-console.js

import { declare } from '@babel/helper-plugin-utils';const removeConsolePlugin = declare((api, options, dirname) => {api.assertVersion(7);return {visitor: {CallExpression(path) {// 检查是否是console.method()调用const { callee } = path.node;if (callee.type === 'MemberExpression' &&callee.object.type === 'Identifier' &&callee.object.name === 'console' &&callee.property.type === 'Identifier') {// 如果是独立语句 (ExpressionStatement),直接移除整个语句if (path.parent.type === 'ExpressionStatement') {path.parentPath.remove();}// 否则,替换为undefined (避免语法错误)else {path.replaceWith(api.types.identifier('undefined'));}return;}},},};
});export default removeConsolePlugin;

为什么要处理这些呢

 callee.type === 'MemberExpression' &&callee.object.type === 'Identifier' &&callee.object.name === 'console' &&callee.property.type === 'Identifier'

在https://astexplorer.net/ 可以尝试下
在这里插入图片描述

当然也可以写成这样

 visitor: {MemberExpression(path){if(path.node.object.name=='console'){console.log(path.parentPath.node)path.parentPath.remove();}}},

rollup-plugin-remove-console.js

import { createFilter } from '@rollup/pluginutils';
import { transformFromAstSync } from '@babel/core';
import parser from '@babel/parser';
import removeConsolePlugin from './babel-plugin-remove-console';
export default function myPlugin(pluginOptions = {}) {const defaultExclude = /node_modules/;// 如果用户提供了exclude选项,合并默认排除const excludePattern = pluginOptions.exclude? [defaultExclude, pluginOptions.exclude]: defaultExclude;const filter = createFilter(pluginOptions.include || /\.(js|ts|jsx|tsx|vue)$/,excludePattern);return {name: 'rollup-plugin-remove-console',transform(src, id) {if (!filter(id)) {return null;}const ast = parser.parse(src, {sourceType: 'unambiguous',});const { code, map } = transformFromAstSync(ast, src, {plugins: [[removeConsolePlugin]],});return {code,map, // 或者提供一个 sourcemap 对象};},};
}

vite.config.js引入使用

在这里插入图片描述
如果你使用了多个插件,需要把自己定义的这个去除插件放到最后面,等其他代码都转换完毕后,只需要处理js语法即可。
比如我们这里引入了vuejsx,支持vuejsx语法。
在这里插入图片描述

他是怎么处理的呢。
一般vue编译的时候,会把vue文件中的,样式,模版,脚本拆分。
在这里插入图片描述

我这里的jsx写法,所以是lang.jsx
在这里插入图片描述
经过vue,vuejsx插件的加工后,成了这样
在这里插入图片描述
所以我们只需要考虑console本身即可。

扩展

忽略某些

增加配置来处理,如,我们可以配置console的哪些方法不移除或者哪些方法移除。
在这里插入图片描述
在vite插件中,将pluginOptions传递给babel插件,这里文件名起的是rollup-plugin-remove-console.js因为没用到vite的特性hooks所以也支持rollup(按理来说,不过没有测试)。

在这里插入图片描述
在这里插入图片描述
可以看到传递过来的参数。
在这里插入图片描述

怎么获取是log还是warn还是error呢。
在这里插入图片描述

在这里插入图片描述
所以要获取下 const name = path.node.property.name;

import { declare } from '@babel/helper-plugin-utils';
const removeConsolePlugin = declare((api, options, dirname) => {api.assertVersion(7);const ignores = options.ignore || [];return {visitor: {MemberExpression(path) {if (path.node.object.name == 'console') {const name = path.node.property.name;const isIgnore = ignores.includes(name);if (!isIgnore) {path.parentPath.remove();}}},},};
});export default removeConsolePlugin;

或者

import { declare } from '@babel/helper-plugin-utils';
const removeConsolePlugin = declare((api, options, dirname) => {api.assertVersion(7);const ignores = options.ignore || [];return {visitor: {CallExpression(path) {// 检查是否是console.method()调用const { callee } = path.node;if (callee.type === 'MemberExpression' &&callee.object.type === 'Identifier' &&callee.object.name === 'console' &&callee.property.type === 'Identifier') {const name = callee.property.name;const isIgnore = ignores.includes(name);if (!isIgnore) {// 如果是独立语句 (ExpressionStatement),直接移除整个语句if (path.parent.type === 'ExpressionStatement') {path.parentPath.remove();}// 否则,替换为undefined (避免语法错误)else {path.replaceWith(api.types.identifier('undefined'));}}}},},};
});export default removeConsolePlugin;

在这里插入图片描述

替换

比如我们有这样两个个函数。上报数据,上报异常。
在这里插入图片描述
假设,在开发环境我们不需要上报,也就是开发环境不替换,一般也是开发环境不替换。
我们需要在插件运行前获取环境
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
传递给babel插件
在这里插入图片描述
当然其实这一步不用,你可以在babe插件里面直接获取。
在babel插件里面接收下。在这里插入图片描述

如果不是开发环境就执行插件。
在这里插入图片描述
或者我们简单点。

在vite插件中直接不往下走了,不执行babel插件了。
在这里插入图片描述
然后继续完善替换的逻辑。
假设我们的插件是这样传递参数的。
在这里插入图片描述
babel获取下
在这里插入图片描述

替换的逻辑为
当匹配上的时候,把原先的参数带进去,再额外携带一个文件的信息。

在这里插入图片描述

source为来源。
在这里插入图片描述
source大概这样
在这里插入图片描述
然后我们看下效果。
开发环境
在这里插入图片描述

build后
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

完整代码

rollup-plugin-remove-console.js

rollup-plugin-remove-console.js

import { createFilter } from '@rollup/pluginutils';
import { transformFromAstSync } from '@babel/core';
import parser from '@babel/parser';
import removeConsolePlugin from './babel-plugin-remove-console';
export default function myPlugin(pluginOptions = {}) {const defaultExclude = /node_modules/;let isDev = false;// 如果用户提供了exclude选项,合并默认排除const excludePattern = pluginOptions.exclude? [defaultExclude, pluginOptions.exclude]: defaultExclude;const filter = createFilter(pluginOptions.include || /\.(js|ts|jsx|tsx|vue)$/,excludePattern);// console.log(pluginOptions);return {name: 'rollup-plugin-remove-console',options(inputOptions) {isDev = process.env.NODE_ENV === 'development';console.log('isDev', isDev);return inputOptions;},transform(src, id) {if (!filter(id) || isDev) {return null;}const ast = parser.parse(src, {sourceType: 'unambiguous',});const paths = id.split('/');const source = paths[paths.length - 1];console.log(source);const { code, map } = transformFromAstSync(ast, src, {plugins: [[removeConsolePlugin, { ...pluginOptions, source, isDev }]],});return {code,map, // 或者提供一个 sourcemap 对象};},};
}

babel-plugin-remove-console.js

babel-plugin-remove-console.js

import { declare } from '@babel/helper-plugin-utils';
import { types as t } from '@babel/core';const removeConsolePlugin = declare((api, options, dirname) => {api.assertVersion(7);const ignores = options.ignore || [];const replaceList = options.replaceList || [];const source = options.source;let isDev = process.env.NODE_ENV == 'development';if (typeof options.isDev != 'undefined') {isDev = options.isDev;}return {visitor: {MemberExpression(path) {if (path.node.object.name == 'console' && !isDev) {const name = path.node.property.name;const replaceItem = replaceList.find((item) => item[0] === name);if (replaceItem) {const replaceName = replaceItem[1];if (!replaceName) {console.warn('请配置替换的函数');}if (replaceList.length > 0) {const args = path.parentPath.node.arguments;const loggerCall = t.callExpression(t.identifier(replaceName), [...args,t.stringLiteral(source),]);loggerCall.isDone = true;path.parentPath.replaceWith(loggerCall);}}const isIgnore = ignores.includes(name);if (!isIgnore) {path.parentPath.remove();}}},},};
});export default removeConsolePlugin;

vite.config.js

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import rollupPluginRemoveConsole from './rollup-plugin-remove-console.js';
import vueJsx from '@vitejs/plugin-vue-jsx';// https://vite.dev/config/
export default defineConfig({//plugins: [vue(),vueJsx(),rollupPluginRemoveConsole({ignore: ['log', 'error'],replaceList: [['log', 'uploadLog'],['error', 'uploadError'],],}),],base: './',server: {proxy: {'/api': {target: 'http://localhost:3000/',changeOrigin: true,rewrite: (path) => path.replace(/^\/api/, ''),},},},
});

main.js

import { createApp } from 'vue';
import './style.css';
import App from './App.vue';const upData = (type, args) => {fetch(`/api/${type}`, {method: 'POST',headers: {'Content-Type': 'application/json',},body: JSON.stringify(args),});
};window.uploadLog = (...args) => {upData('log', args);
};
window.uploadError = (...args) => {upData('error', args);// fetch
};createApp(App).mount('#app');
http://www.lryc.cn/news/571566.html

相关文章:

  • el-upload 点击上传按钮前先判断条件满足再弹选择文件框
  • Python 构建壳来启动加密的 SpringBoot Jar 包,增加反编译难度
  • 亚远景-ASPICE与ISO 26262:理解汽车软件质量保障的双标体系
  • 小米汽车5月交付量超过28000台,与上月持平
  • STM32 GPIO 寄存器开发
  • Linux设备框架:kset与kobject基本介绍
  • Dify动手实战教程(入门-猜病、哄哄模拟器)
  • 树结构的实际应用之堆排序
  • 【redis】安装与使用
  • 【开源解析】基于Python+Qt打造智能应用时长统计工具 - 你的数字生活分析师
  • web和uniapp接入腾讯云直播
  • 胰腺癌耐药机制新发现:超级增强子如何调控吉西他滨敏感性
  • 【Linux】基于单例模式的线程池设计
  • 构建智能问答系统:从零开始实现 RAG 应用
  • MySQL常用函数详解之流程函数
  • 逆向入门(12)程序逆向篇-Acid burn
  • Docker Compose部署Spring Cloud 微服务系统
  • CppCon 2016 学习:On using singletons in C++
  • 14.2 《3小时从零搭建企业级LLaMA3语言助手:GitHub配置+私有化模型集成全实战》
  • Uniapp性能优化全面指南:从原理到实践
  • 从0开始学习R语言--Day26--因果推断
  • 4. 时间序列预测的自回归和自动方法
  • Docker学习笔记:数据卷
  • 秋招是开发算法一起准备,还是只准备一个
  • 【CUDA编程】OptionalCUDAGuard详解
  • 【6G技术探索】MCP协议整理分享
  • 6.IK分词器拓展词库
  • # 我使用过的 HTML + CSS 实践总结笔记(含说明)
  • 设计模式笔记_创建型_工厂模式
  • 九日集训第六天