vue中重写并自定义console.log
0. 背景
在vue2项目中自定义console.log并输出文件名及行、列号
1. 实现
1.1 自定义console.log

export default {// 输出等级: 0-no, 1-error, 2-warning, 3-info, 4-debug, 5-loglevel: 5,// 输出模式: 0-default, 1-normal, 2-randommode: 1,// 是否输出图标hasIcon: false,// 是否在vue内使用isVue: true,// 是否打印函数名和所在文件行号isPrintLine: true,// 图标icons: ['🌵', '🎍', '🐾', '🌀', '🐚', '🥝', '🥜', '🥕', '🥒', '🌽', '🍒', '🍅', '🍑', '🍋', '🍈', '🌶', '🌰', '🍠', '🍆', '🍄', '🍐', '🍌', '🍍', '🍇', '🍏', '🍓', '🍎', '🍊', '🐴', '🐗', '🦄', '🐑', '🐶', '🐔', '🐼', '🐒', '🌝', '💄', '💋', '👠', '👗', '👙', '🧣', '🍰', '🍭', '🍳', '🎄', '🎱', '⚽', '🏀', '🎵', '🚄', '⭕', '❌', '❓', '❗', '💯'],// 标准颜色colors: {error: '#f7630c',warning: '#ca5010',info: '#0078d7',debug: '#13a10e',log: '#1f1f1f'},// 获取随机图标randomIcon: function () {return this.icons[Math.floor(Math.random() * this.icons.length)]},// 获取随机颜色randomColor: function () {const r = Math.floor(Math.random() * 256)const g = Math.floor(Math.random() * 256)const b = Math.floor(Math.random() * 256)// 返回随机生成的颜色return `rgb(${r}, ${g}, ${b})`},// 默认打印printDefault: function (tag, args) {console.log(tag, ...args)},// 标准打印printNormal: function (tag, args) {console.log(`%c ${tag} : `, `color: ${this.colors[tag]}`, ...args)},// 随机打印printRandom: function (tag, args) {const icon = this.randomIcon()const bgColor = this.randomColor()const color = this.randomColor()console.log(`%c ${icon}`, `font-size:20px;background-color: ${bgColor};color: ${color};`, tag + ' : ', ...args)},print: function (tag, args) {if (this.isPrintLine) {if (!this.isVue) {// 获取函数名和行号const err = new Error()// console.log(err.stack)const stack = err.stack.split('\n').slice(3).map(line => line.trim())// console.log(stack)const caller = stack[0].match(/at (.+) \(/) ? stack[0].match(/at (.+) \(/)[1] : stack[0].match(/at (.+):\d+:/)[1]const fileLine = stack[0].match(/\(.*\/(.+)\)/) ? stack[0].match(/\(.*\/(.+)\)/)[1] : stack[0].match(/(\d+:\d+)/)[1]// console.log(`${caller} (${fileLine}):\n`)args.shift(`[${caller} (${fileLine})]\n`)} else {args.shift()}} else {if (this.isVue) {args.shift().shift()}}switch (this.mode) {case 0: {this.printDefault(tag, args)break}case 1: {this.printNormal(tag, args)break}case 2: {this.printRandom(tag, args)break}}},error: (function (oriLogFunc) {return function (...args) {const tag = 'error'if (this.level >= 1) {// oriLogFunc.call(console, 'error : ', args)this.print(tag, args)}}})(console.log),warning: (function (oriLogFunc) {return function (...args) {const tag = 'warning'if (this.level >= 2) {// oriLogFunc.call(console, 'warning : ', args)this.print(tag, args)}}})(console.log),info: (function (oriLogFunc) {return function (...args) {const tag = 'info'if (this.level >= 3) {// oriLogFunc.call(console, 'info : ', args)this.print(tag, args)}}})(console.log),debug: (function (oriLogFunc) {return function (...args) {const tag = 'debug'if (this.level >= 4) {// oriLogFunc.call(console, 'debug : ', ...args)this.print(tag, args)}}})(console.log),log: (function (oriLogFunc) {return function (...args) {const tag = 'log'if (this.level >= 5) {// oriLogFunc.call(console, 'log : ', ...args)this.print(tag, args)}}})(console.log)
}
1.2 webpack记录行号
添加自定义
loader

module.exports = function (content) {content = content.toString('utf-8')if (this.cacheable) this.cacheable()const { name = ['this.\\$iceLog.log'] } = this.query.config || {}const fileName = this.resourcePath.replaceAll('\\', '/').match(/(?<=\/)(src.*)/gm)[0]content = content.split('\n').map((line, row) => {let loggerName = name[0]for (let i = 1; i < name.length; i++) {loggerName += '|' + name[i]}const re = new RegExp(`(${loggerName})\\((.*?)\\)`, 'g')let resultlet newLine = ''let cursor = 0while ((result = re.exec(line))) {const col = result.indexnewLine += line.slice(cursor, result.index) + `${result[1]}('[${fileName}:${row + 1}:${col + 1}]\\n', ` + result[2] + ')'cursor += col + result[0].length}newLine += line.slice(cursor)return newLine}).join('\n')return content
}
module.exports.raw = true
1.3 配置loader
修改
vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({transpileDependencies: true,lintOnSave: false,chainWebpack: config => {// config.devtool('eval-cheap-module-source-map')config.module.rule('vue').use('vue-loader').end().rule('log-lineno').use('./loaders/log-lineno.loader').loader('./loaders/log-lineno.loader').options({config: {name: ['this.\\$iceLog.error','this.\\$iceLog.warning','this.\\$iceLog.info','this.\\$iceLog.debug','this.\\$iceLog.log']}}).end()}
})
2. 测试
created () {this.$iceLog.log(123)this.$iceLog.error(1, 2, 3, 4)},

3. 问题
3.1 .vue文件被编译多次,自定义log会输出两个目录

解决:
在自定义函数中移除一个参数:

x. 参考
- 重写并自定义console.log()输出样式
- 巧用 webpack 在日志中记录文件行号
- vue webpace相关
- Vue2工程化 webpack配置 loader插件
- webpack初学者看这篇就够了
- 你了解webpack中配置的loader的执行顺序吗?
相关文章:
vue中重写并自定义console.log
0. 背景 在vue2项目中自定义console.log并输出文件名及行、列号 1. 实现 1.1 自定义console.log export default {// 输出等级: 0-no, 1-error, 2-warning, 3-info, 4-debug, 5-loglevel: 5,// 输出模式: 0-default, 1-normal, 2-randommode: 1,// 是否输出图标hasIcon: fal…...
基于OpenCV 和 Dlib 进行头部姿态估计
写在前面 工作中遇到,简单整理博文内容涉及基于 OpenCV 和 Dlib头部姿态评估的简单Demo理解不足小伙伴帮忙指正 庐山烟雨浙江潮,未到千般恨不消。到得还来别无事,庐山烟雨浙江潮。 ----《庐山烟雨浙江潮》苏轼 https://github.com/LIRUILONGS…...
24个Jvm面试题总结及答案
1.什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? Java虚拟机是一个可以执行Java字节码的虚拟机进程。Java源文件被编译成能被Java虚拟机执行的字节码文件。 Java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每…...
freemarker 生成前端文件
Freemarker是一种模板引擎,它允许我们在Java应用程序中分离视图和业务逻辑。在Freemarker中,List是一种非常有用的数据结构,它允许我们存储一组有序的元素。有时候,我们需要判断一个List是否为空,这在程序设计中有许多…...
Pycharm+pytest+allure打造高逼格的测试报告
目录 前言: 1、安装allure 2、安装allure-pytest 3、一个简单的用例test_simpe.py 4、在pycharm底部打开terminal 5、用allure美化报告 6、查看报告 总结: 前言: 今天分享的内容:在Pycharmpytest基础上使用allure打造高逼格…...
Mybatis-Plus中update更新操作用法
目录 一、前言二、update1、关于修改的4个条件构造器2、UpdateWrapper【用法示例】3、LambdaUpdateWrapper【用法示例】4、UpdateChainWrapper【 用法示例】5、LambdaUpdateChainWrapper【 用法示例】6、updateById 和 updateBatchById7、Mybatis-plus设置某个字段值为null的方…...
16道JVM面试题
1.jvm内存布局 1.程序计数器:当前线程正在执行的字节码的行号指示器,线程私有,唯一一个没有规定任何内存溢出错误的情况的区域。 2.Java虚拟机栈:线程私有,描述Java方法执行的内存模型,每个方法运行时都会…...
HttpRunner 接口自动化测试框架实战,打造高效测试流程
简介 2018年python开发者大会上,了解到HttpRuuner开源自动化测试框架,采用YAML/JSON格式管理用例,能录制和转换生成用例功能,充分做到用例与测试代码分离,相比excel维护测试场景数据更加简洁。在此,利用业…...
手写一个webpack插件(plugin)
熟悉 vue 和 react 的小伙伴们都知道,在执行过程中会有各种生命周期钩子,其实webpack也不例外,在使用webpack的时候,我们有时候需要在 webpack 构建流程中引入自定义的行为,这个时候就可以在 hooks 钩子中添加自己的方…...
jvm常见面试题
0x01. 内存模型以及分区,需要详细到每个区放什么。 栈区: 栈分为java虚拟机栈和本地方法栈 重点是Java虚拟机栈,它是线程私有的,生命周期与线程相同。 每个方法执行都会创建一个栈帧,用于存放局部变量表࿰…...
TF-A 项目的长期支持介绍
引流关键词:Armv8-A, Armv9-A, Cortex-A, Cortex-A12, Cortex-A15, Cortex-A17, Cortex-A32, Cortex-A34, Cortex-A35, Cortex-A5, Cortex-A510, Cortex-A53, Cortex-A55, Cortex-A57, Cortex-A65, Cortex-A65AE, Cortex-A7, Cortex-A710, Cortex-A715, Cortex-A72, Cortex-A7…...
企业电子招标采购系统源码java 版本 Spring Cloud + Spring Boot
项目说明 随着公司的快速发展,企业人员和经营规模不断壮大,公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境,最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范,以及…...
7.Mysql 事务底层
一、事务的基础知识 mysql中的事务 分为 显式事务 和 隐式事务。 1.1 显式事务 显式事务就是我们手动开启事务,并且提交事务比如: -- 开启事务 begin; -- 执行查询语句 select *from where id = 1 for update ; -- 提交事务 commit;1.2 隐式事务 在 MySQL 中,隐式事务是…...
15.DIY可视化-拖拽设计1天搞定主流小程序-分类联动文章列表实时刷新
分类联动文章列表实时刷新 本教程均在第一节中项目启动下操作 分类联动文章列表实时刷新前言需求一:功能实现:点击首页分类,对应分类内容显示到当前页一、清空原分类界面:二. 设置选项卡三:设定展示内容字段:1.跨页面复制:文章分类组件到分类
CRect rect; this->GetClientRect(rect); pDC->Ellipse(rect); // DDALineView.cpp : implementation of the CDDALineView class // #include “stdafx.h” #include “DDALine.h” #include “DDALineDoc.h” #include “DDALineView.h” #ifdef _DEBUG #define new…...
Spark大数据处理学习笔记(3.2.1)掌握RDD算子
该文章主要为完成实训任务,详细实现过程及结果见【http://t.csdn.cn/FArNP】 文章目录 一、准备工作1.1 准备文件1. 准备本地系统文件2. 把文件上传到 1.2 启动Spark Shell1. 启动HDFS服务2. 启动Spark服务3. 启动Spark Shell 二、掌握转换算子2.1 映射算子 - map()…...
lammps初级:石墨烯、金属材料、纳米流体、热传导、多成分体系、金属、半导体材料的辐照、自建分子力场、MOFS、H2/CO2混合气体等模拟
1 LAMMPS的基础入门——初识LAMMPS是什么?能干什么?怎么用? 1.1 LAMMPS在win10和ubuntu系统的安装及使用 1.2 in文件结构格式 1.3 in文件基本语法:结合实例,讲解in文件常用命令 1.4 data文件格式 1.5 LAMMPS常见错误解…...
【MarkerDown】CSDN Markdown之时序图sequenceDiagram详解
CSDN Markdown之时序图sequenceDiagram详解 序列图 sequenceDiagram参与者与组参与者 participant拟人符号 actor别名 as组 box 消息(连线)激活/失活 activate/deactivate备注 Note循环 loop备选 Alt并行 par临界区 critical中断 break背景高亮 rect注释 %%转义字符的实体代码序…...
ReentrantLock实现原理-公平锁
在ReentrantLock实现原理(1)一节中,我们了解了ReentrantLock非公平锁的获取流程,在本节中我们来看下ReentrantLock公平锁的创建以及锁管理流程 创建ReentrantLock公平锁 创建公平锁代码如下: ReentrantLock reentrantLock new ReentrantL…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
