前端监控之sourcemap精准定位和还原错误源码

一、概述

在前端开发中,监控和错误追踪是确保应用稳定性和用户体验的重要环节。

随着前端应用的复杂性增加,JavaScript错误监控变得尤为重要。在生产环境中,为了优化加载速度和性能,前端代码通常会被压缩和混淆。这虽然提升了性能,但也给错误追踪带来了挑战,因为错误报告中显示的代码位置和实际代码不一致,使得开发者难以定位和修复问题。

Sourcemap技术应运而生,它是一种将压缩后的代码映射回原始源代码的工具。通过sourcemap,开发者可以准确地从错误报告中找到原始代码中的问题所在,即使这些代码已经被压缩或混淆。这种映射关系使得错误追踪变得更加精确和高效。

在这篇文章中,将探讨如何在前端项目中集成sourcemap,以及如何利用sourcemap进行错误监控和代码还原。我将介绍sourcemap的生成、部署和使用,以及它在前端监控中的最佳实践。通过这些内容,同学们将能够理解sourcemap在前端错误监控中的重要性,并学会如何利用这一工具提高开发效率和应用质量。

二、实践

通过sourcemap技术实现对前端代码中错误位置的精确定位和还原。

2.1、Sourcemap结构

Sourcemap文件通常包含以下字段:

  • version:Sourcemap的版本,目前常用的是版本3。
  • file:转换后的文件名。
  • sourceRoot:源文件的根目录路径,用于重新定位源文件。
  • sources:源文件列表,可能包含多个文件。
  • sourcesContent:源文件的内容列表(可选)。
  • names:转换前的变量名和属性名列表。
  • mappings:一个编码的字符串,记录了源代码和转换后代码之间的详细映射关系。

2.2、初始化项目

使用我自己实现的前端action-cli脚手架,从自己GitHub仓库拉取模板并初始化一个Vite+Vue3+TS项目,安装依赖运行项目。

更多关于action-cli可以查看这两篇文章

实现一个自定义前端脚手架_前端自定义脚手架-CSDN博客

重构Action-cli前端脚手架-CSDN博客

添加下面两个路由

const routes=[{path: '/errorView',name: 'ErrorView',component: () => import('@/views/sourcemap/ErrorView.vue'),meta: {title: '生产错误'}},{path: '/errorList',name: 'ErrorList',component: () => import('@/views/sourcemap/ErrorList.vue'),meta: {title: '错误列表'}}
];// https://github.com/Topskys/admin-pro/tree/monitor

2.3、生产Js错误

创建./views/sourcemap/ErrorView.vue页面,通过throw模拟抛出Js代码错误。

// ./views/sourcemap/ErrorView.vue
<template><div><h1>Error</h1><button @click="triggerTypeError()">触发TypeError</button><button @click="triggerReferenceError">触发ReferenceError</button><button @click="triggerSyntaxError">触发SyntaxError</button></div>
</template>
<script setup lang="ts">
const triggerTypeError = () => {throw new TypeError('This is a type error');
};const triggerReferenceError = () => {throw new ReferenceError('This is a reference error');
};const triggerSyntaxError = () => {throw new SyntaxError('This is a syntax error');
};
</script>

配置vite.config.ts,将该页面打包成单个文件,并且需要开启sourcemap,方便测试。

// ...
build: {sourcemap: true,rollupOptions: {input: {index: fileURLToPath(new URL('./index.html', import.meta.url))},output: {// 将依赖单独打包manualChunks: (id: string) => {if (id.includes('node_modules')) {return 'vendor';}if (id.includes('src/views/sourcemap/ErrorView')) {return 'errorView';}return 'index';},}}
},

2.4、捕捉Js错误

这里需要安装两个依赖包,分别用于解析错误和解析sourcemap文件。

pnpm i error-stack-parser source-map-js

Vue3提供了一个捕捉全局错误的回调函数app.config.errorHandler,去main.ts实现这个方法的回调函数。

// main.ts
// ...// 捕捉错误
app.config.errorHandler = (err: any, vm, info) => {console.log('err', err, '\nvm', vm, '\ninfo', info);const errorStack = ErrorStackParser.parse(err as Error);console.log('errorStack', errorStack);
}

点击触发TypeError,errorHandler函数就会捕捉到错误,并打印出错误和 error-stack-parser处理err后的效果

把错误信息存储到localStorage,方便其他页面展示错误列表信息。 

import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import ErrorStackParser from 'error-stack-parser';const app = createApp(App);
app.use(router);// 捕捉错误
app.config.errorHandler = (err: any, vm, info) => {const errorStack = ErrorStackParser.parse(err as Error);const jsError = {stack_frames: errorStack,message: err.message,stack: err.stack,error_name: err.name};console.error(`触发一个${err.name}错误`);localStorage.setItem('jsErrorList', JSON.stringify(jsError));
}app.mount('#app');

2.5、展示错误列表

新建./views/sourcemap/ErrorList.vue错误列表页面,用于展示错误信息和映射到源码操作。

<template><div v-if="isErr"><pre>{{ js_error.stack }}</pre><el-collapse v-model="activeNames" @change="handleChange"><el-collapse-item v-for="(item, index) in js_error.stack_frames" :key="index" :title="item.source" :name="index"><el-row :gutter="20"><el-col :span="20">{{ item.fileName }}</el-col><el-col :span="4"><el-button type="primary" size="small" @click="openDialog(item, index)">映射源码</el-button></el-col></el-row><el-row :gutter="20"><template v-if="item.originalSource">{{ item.originalSource }}<!-- <Preview :origin="item.originalSource" /> --></template><template v-else>{{ item.functionName }}</template></el-row></el-collapse-item></el-collapse><el-dialog v-model="dialogVisible" title="SourceMap源码映射" width="500"><el-tabs v-model="tabActiveName"><el-tab-pane label="本地上传" name="local"><el-upload drag :before-upload="sourcemapUpload"><i class="el-icon-upload"></i><div>将文件拖拽到此处,或者<em>点击上传</em></div></el-upload></el-tab-pane><el-tab-pane label="远程加载" name="remote"> </el-tab-pane></el-tabs></el-dialog></div>
</template>
<script setup lang="ts">
// https://github.com/Topskys/admin-pro/tree/monitor/src/views/sourcemap
</script>

从localStorage获取错误数据初始化列表

const getErrorList = () => {try {const errorString = localStorage.getItem('jsErrorList');if (!errorString) return;js_error.value = JSON.parse(errorString);isErr.value = true;} catch (error: any) {console.log('获取错误列表失败', error);}
};onMounted(() => {getErrorList();
});

弹窗用于上传本地打包后的sourcemap文件。

// 打开弹窗
const openDialog = (item: any, index: number) => {dialogVisible.value = true;stackFrameObj = {line: item.lineNumber, // 错误代码行号column: item.columnNumber, // 错误代码列号index: index // 列表需序号};
};

 错误列表

处理sourcemap上传事件和解析 

const sourcemapUpload = async (file: any) => {if (file.name.substring(file.name.lastIndexOf('.') + 1) !== 'map') {ElMessage({message: '请上传正确的sourcemap文件',type: 'error'});return;}const reader = new FileReader();reader.readAsText(file);reader.onload = async function (e: any) {const code = await getSource(e?.target?.result, stackFrameObj.line, stackFrameObj.column);js_error.value.stack_frames[stackFrameObj.index].originalSource = code;dialogVisible.value = false;};return false; // 不写这一行会报错
};

获取报错ErrorView.vue页面的sourcemap文件,一般真实项目会把打包后的源码和sourcemap文件分别部署到不同的服务器,来提升安全性。 注意在本地不能还原,上传sourcemap后会报错404,因此需要把项目部署到github 静态资源服务器。

// 请求并解析sourcemap文件
const getSource = async (sourcemap: any, line: number, column: number) => {try {const consumer = await new sourceMap.SourceMapConsumer(JSON.parse(sourcemap));const originalPosition = consumer.originalPositionFor({ line, column });const source = consumer.sourceContentFor(originalPosition.source);// console.log('本地报错404source', source);return {source: source,line: originalPosition.line,column: originalPosition.column};} catch (e) {ElMessage.error('sourcemap解析失败');}
};

2.6、错误源代码展示

新建./views/sourcemap/Preview.vue组件,用于处理和展示还原后的源代码。

<template><div class="pre-code"><div class="error-detail"><pre class="error-code" v-html="preLine()"></pre></div></div>
</template>
// js部分可参考github仓库monitor分支
// https://github.com/Topskys/admin-pro/tree/monitor

2.7、构建CI/CD

基于github actions构建ci/cd流水线,这里就不详细赘述了,不知道的同学可以阅读这篇文章基于Github Actions实现前端CI/CD持续集成与部署_github cicd-CSDN博客 

把触发流水线的分支改成monitor分支,因为当前是在monitor发开并测试sourcemap映射源代码。

三、效果

3.1、触发ci/cd

运行打包命令

提交代码到monitor分支触发流水线自动化部署。

3.2、测试还原

测试sourcemap还原错误源代码,访问https://topskys.github.io/admin-pro/#/生产错误页面,点击触发错误按钮触发错误。

打开错误列表页面,可以看到错误信息生成。展开列表第一个错误,点击映射源码。

 选择上传errorView.vue报错页面对应的map文件(真正项目线上环境从其它服务器获取map文件),以解析出源代码。

 上传之后,就能看到错误列表中已经还原出精准的行错误源代码(标红行)了,行号和源代码都一致。

 具体代码实现过程可前往github仓库的monitor分支查看

admin-pro/src/views/sourcemap at monitor · Topskys/admin-proicon-default.png?t=O83Ahttps://github.com/Topskys/admin-pro/tree/monitor/src/views/sourcemap

四、参考

基于Github Actions实现前端CI/CD持续集成与部署_github cicd-CSDN博客

重构Action-cli前端脚手架-CSDN博客

实现一个自定义前端脚手架_前端自定义脚手架-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/61149.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL的表的约束以及查询

本篇文章继续给大家梳理MySQL的操作 目录 表的约束 空属性 默认值 列描述 0填充 主键 主键常识 添加主键 删除主键 复合主键 自增长 唯一键 外键 单/多行输入与全/指定列的插入 全列输入 单行输入 多行插入 指定列插入 单行输入 多行插入 插入否则更新 替换…

MySQL 日志 主从复制

1. 日志 学习链接&#xff0c;click mysql中有4种日志&#xff1a; 错误日志二进制日志查询日志慢查询日志 1.1 错误日志 错误日志是MySQL中最重要的日志之一&#xff0c;它记录了当mysqld启动和停止时&#xff0c;以及服务器在运行过程中发生任何严重错误时的相关信息。当…

自动驾驶系列—深入解析自动驾驶车联网技术及其应用场景

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

基于YOLOv8深度学习的公共卫生防护口罩佩戴检测系统(PyQt5界面+数据集+训练代码)

在全球公共卫生事件频发的背景下&#xff0c;防护口罩佩戴检测成为保障公众健康和控制病毒传播的重要手段之一。特别是在人员密集的公共场所&#xff0c;例如医院、学校、公共交通工具等地&#xff0c;口罩的正确佩戴对降低病毒传播风险、保护易感人群、遏制疫情扩散有着至关重…

vue使用List.reduce实现统计

需要对集合的某些元素的值进行计算时&#xff0c;可以在计算属性中使用forEach方法 1.语法&#xff1a;集合.reduce ( ( 定义阶段性累加后的结果 , 定义遍历的每一项 ) > 定义每一项求和逻辑执行后的返回结果 , 定义起始值 ) 2、简单使用场景&#xff1a;例如下面…

【Linux】进程的优先级

进程的优先级 一.概念二.修改优先级的方法三.进程切换的大致原理&#xff1a;四.上下文数据的保存位置&#xff1a; 一.概念 cpu资源分配的先后顺序&#xff0c;就是指进程的优先权&#xff08;priority&#xff09;。 优先权高的进程有优先执行权利。配置进程优先权对多任务环…

【软件工程】一篇入门UML建模图(类图)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;软件开发必练内功_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前…

AWTK-WIDGET-WEB-VIEW 实现笔记 (3) - MacOS

MacOS 上实现 AWTK-WIDGET-WEB-VIEW 有点麻烦&#xff0c;主要原因是没有一个简单的办法将一个 WebView 嵌入到一个窗口中。所以&#xff0c;我们只能通过创建一个独立的窗口来实现。 1. 创建窗口 我对 Object-C 不熟悉&#xff0c;也不熟悉 Cocoa 框架&#xff0c;在 ChatGPT…

QT仿QQ聊天项目,第三节,实现聊天界面

一&#xff0c;界面控件示意图 界面主要由按钮QPushButton,标签QLabel,列表QListWidget 要注意的是QListWidget既是实现好友列表的控件&#xff0c;也是实现聊天气泡的控件 二&#xff0c;控件样式 QPushButton#btn_name {border:none;}QPushButton#btn_close {border:1px;bac…

微信小程序自定义顶部导航栏(适配各种机型)

效果图 1.pages.js&#xff0c;需要自定义导航栏的页面设置"navigationStyle": "custom" 2.App.vue,获取设备高度及胶囊位置 onLaunch: function () {// 系统信息const systemInfo uni.getSystemInfoSync()// 胶囊按钮位置信息const menuButtonInfo uni.…

Android Studio开发学习(五)———LinearLayout(线性布局)

一、布局 认识了解一下Android中的布局&#xff0c;分别是: LinearLayout(线性布局)&#xff0c;RelativeLayout(相对布局)&#xff0c;TableLayout(表格布局)&#xff0c; FrameLayout(帧布局)&#xff0c;AbsoluteLayout(绝对布局)&#xff0c;GridLayout(网格布局) 等。 二、…

C++:哈希拓展-位图

目录 一.问题导入 二.什么是位图? 2.1如何确定目标数在哪个比特位? 2.2如何存放高低位 2.3位图模拟代码实现 2.3.1如何标记一个数 2.3.2如何重置标记 2.3.3如何检查一个数是否被标记 整体代码实现 标准库的Bitset 库中的bitset的缺陷 简单应用 一.问题导入 这道…

实用教程:如何无损修改MP4视频时长

如何在UltraEdit中搜索MP4文件中的“mvhd”关键字 引言 在视频编辑和分析领域&#xff0c;有时我们需要深入到视频文件的底层结构中去。UltraEdit&#xff08;UE&#xff09;和UEStudio作为强大的文本编辑器&#xff0c;允许我们以十六进制模式打开和搜索MP4文件。本文将指导…

Spring Boot 接口防重复提交解决方案

文章目录 前言使用Token机制实现步骤1.生成Token2.传递Token3.验证Token 使用Redis实现步骤1.引入Redis依赖2.生成Token3.传递Token4.验证Token 使用Spring AOP实现步骤1.定义注解2.创建切面3.使用注解 总结 前言 在Web开发中&#xff0c;防止用户重复提交表单是一个常见的需求…

Linux性能优化之火焰图简介

Linux 火焰图&#xff08;Flame Graph&#xff09;是一种可视化工具&#xff0c;用于分析程序性能问题&#xff0c;尤其是 CPU 使用情况。它展示了程序中函数调用的层次结构和各个调用栈占用的时间比例。 以下是详细介绍&#xff0c;包括火焰图的工作原理、生成步骤和实际使用中…

笔记|M芯片MAC (arm64) docker上使用 export / import / commit 构建amd64镜像

很简单的起因&#xff0c;我的东西最终需要跑在amd64上&#xff0c;但是因为mac的架构师arm64&#xff0c;所以直接构建好的代码是没办法跨平台运行的。直接在arm64上pull下来的docker镜像也都是arm64架构。 检查镜像架构&#xff1a; docker inspect 8135f475e221 | grep Arc…

【JavaWeb】JavaWeb入门之XML详解

目录 1.XML介绍 1.1.XML概述 1.1.1.什么是XML 1.1.2.XML的作用 1.1.3.XML与HTML的比较 1.1.4.XML和properties&#xff08;属性文件&#xff09;比较 1.1.5.W3C组织 1.2.XML语法概述 1.2.1.XML文档展示 1.2.2.XML文档的组成部分 1.3.XML文档声明 1.3.1.什么是XML文…

spring源码02-spring容器启动(容器初始化+bean实例化)源码解读【常见面试题】

文章目录 【README】【1】spring容器初始化及bean实例化步骤列表【2】spring容器初始化源码【2.1】容器初始化主要步骤总结&#xff1a;【2.2】容器初始化详细步骤源码分析 【3】bean实例化源码【3.1】bean实例化主要步骤总结&#xff08;非常重要&#xff09;【3.1.1】 bean生…

Python中的正则表达式教程

一、 正则表达式基础 1。1。概念介绍 正则表达式是用于处理字符串的强大工具,它并不是Python的一部分。 其他编程语言中也有正则表达式的概念,区别只在于不同的编程语言实现支持的语法数量不同。 它拥有自己独特的语法以及一个独立的处理引擎&#xff0c;在提供了正则表达式…

【Python库安装】Python环境安装景观模式分析常用库PyLandStats

【Python库安装】Python环境安装景观模式分析常用库PyLandStats PyLandStats 简介景观分割景观指标 PyLandStats 安装参考 PyLandStats 简介 PyLandStats 是一个用于景观模式分析的 Python 库。它允许用户计算景观格局的各种统计量和指标&#xff0c;广泛应用于生态学、地理信…