前端监控之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博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用Web Push Notifications提升用户参与度和留存率

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Web Push Notifications提升用户参与度和留存率 使用Web Push Notifications提升用户参与度和留存率 使用Web Push Notifica…

量化选股日常操作日记-11-ai眼镜-润欣科技

用 微信小程序 梦想兔企业智能风险分析助手 &#xff0c;选择AI眼镜板块&#xff0c;挖掘了几个合适的股&#xff0c;分析下来感觉 润欣科技 比较安全些适合观察&#xff0c;几块到十几块波动&#xff0c;企业基本面也没有特别大问题。就是现在价位在周期波动高位&#xff0c;下…

【WPF】Prism学习(五)

Prism Commands 1.错误处理&#xff08;Error Handling&#xff09; Prism 9 为所有的命令&#xff08;包含AsyncDelegateCommand&#xff09;提供了更好的错误处理。 避免用try/catch包装每一个方法根据不同遇到的异常类型来提供特定的逻辑处理可以在多个命令之间共享错误处…

Intern大模型训练营(八):Llamaindex RAG 实践

1. 基于 LlamaIndex 构建自己的 RAG 知识库 首先在Intern Studio中申请30% A100的开发机。 进入开发机后&#xff0c;创建新的conda环境&#xff0c;命名为 llamaindex&#xff0c;在命令行模式下运行&#xff1a; conda create -n llamaindex python3.10 复制完成后&#…

台式电脑没有声音怎么办?台式电脑没有声音解决详解

台式电脑一般来说都是没有内置扬声器的&#xff0c;需要连接耳机或者是音响才可以播放音乐。那么如果遇到台式电脑没有声音的问题&#xff0c;我们也需要确认这些设备硬件有没问题&#xff0c;知道原因才可以进行处理。下面本文将为你介绍台式电脑没有声音的可能原因和解决方法…

vue2项目中在线预览csv文件

简介 希望在项目中&#xff0c;在线预览.csv文件&#xff0c;本以为插件很多&#xff0c;结果都只是支持excel&#xff08;.xls、.xlsx&#xff09;一到.csv就歇菜。。。 关于文件预览 vue-office&#xff1a;文档、 查看在线演示demo&#xff0c;支持docx、.xlsx、pdf、ppt…

H.265流媒体播放器EasyPlayer.js视频流媒体播放器关于直播流播放完毕是否能监听到

EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器&#xff0c;可支持多种流媒体协议播放&#xff0c;无须安装任何插件&#xff0c;起播快、延迟低、兼容性强&#xff0c;使用非常便捷。 EasyPlayer.js播放器不仅支持H.264与H.265视频编码格式&#xff0c;也能支持WebS…

WordPress设置自动更新CSS版本号

WordPress 通常会在引用 CSS 文件时添加版本号参数&#xff08;?verx.x.x&#xff09;。如果版本号未更新&#xff0c;浏览器可能继续加载旧的文件。 解决方法&#xff1a;确保你在 functions.php 文件中正确加载了 CSS 文件&#xff0c;并动态更新版本号。例如在functions.p…

【Linux】监控系统Zabbix的安装与配置

文章目录 一、前期准备1、安装LAMP2、配置SELinux与防火墙3、测试Apache4、配置数据库5、创建zabbix数据库及应用 二、server端安装配置1、软件包安装2、配置数据库3、zabbix访问测试4、配置web界面 三、Agent端安装配置1、安装zabbix-agent2、配置3、启动zabbix-agent4、配置防…

Springboot基于GIS的旅游信息管理系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…

HarmonyOs鸿蒙开发实战(17)=>沉浸式效果第二种方案一组件安全区方案

1.沉浸式效果的目的 开发应用沉浸式效果主要指通过调整状态栏、应用界面和导航条的显示效果来减少状态栏导航条等系统界面的突兀感&#xff0c;从而使用户获得最佳的UI体验。 2.组件安全区方案介绍 应用在默认情况下窗口背景绘制范围是全屏&#xff0c;但UI元素被限制在安全区内…

微知-DOCA ARGP参数模块的相关接口和用法(config单元、params单元,argp pipe line,回调)

文章目录 1. 背景2. 设置参数的主要流程2.1 初始化2.2 注册某个params的处理方式以及回调函数2.4 定义好前面的params以及init指定config地点后start处理argv 3. 其他4. DOCA ARGP包相关4.1 主要接口4.2 DOCA ARGP的2个rpm包4.2.1 doca-sdk-argp-2.9.0072-1.el8.x86_64.rpm4.2.…

Linux之vim模式下全选命令

在Linux系统中&#xff0c;使用Vim编辑器进行全选操作可以通过以下几种方式实现&#xff1a; 1.使用键盘快捷键 按下 ”ggVG”&#xff08;先按下”g”&#xff0c;再按下”g”&#xff0c;再按下”V”&#xff0c;最后按下”G”&#xff09;可以全选当前文件内容。其中 ”g…

SQL复杂数据类型处理

背景 数据处理中&#xff0c;经常碰到复杂数据类型&#xff0c;需要将他们进行解析才能利用。 复杂数据类型 1、MAP结构转为列 WITH tmp AS ( SELECT {"Users":{"4418":{"UserId":4418,"Score":0,"IsStudent":true},&q…

下一代以区域为导向的电子/电气架构

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 所有人的看法和评价都是暂时的&#xff0c;只有自己的经历是伴随一生的&#xff0c;几乎所有的担忧和畏惧…

CSS盒子的定位>(上篇)#定位属性#相对定位-附练习

一、定位属性 1.定位方式 position属性可以选择4种不同类型的定位方式。 语法格式&#xff1a;position&#xff1a;relation | absolute | fixed参数&#xff1a;①relative生成相对定位的元素&#xff0c;相对于其正常位置进行定位。 ②absolute生成绝对定位的…

Matlab信号处理:短时傅里叶变换

短时傅里叶变换&#xff08;简称STFT&#xff09;是傅里叶变换在时频域的扩展&#xff0c;它是为分析频域随时间变化的非平稳信号。本文模拟一个啁啾信号&#xff08;一个线性调频的信号&#xff09;&#xff0c;借助matlab的短时傅里叶变换函数stft&#xff0c;分析其时频特性…

Linux网络:基于文件的网络架构

Linux网络&#xff1a;基于文件的网络架构 网络架构TCP全连接队列 网络架构 在Linux中提供了多种系统调用&#xff0c;完成网络操作。比如TCP连接的建立&#xff0c;各种报文的收发等等。但是所有的Linux网络操作&#xff0c;都源于系统调用socket&#xff0c; 在Linux的man手…

【SpringBoot】23 文件预览(kkFileView)

Gitee仓库 https://gitee.com/Lin_DH/system 介绍 文件预览功能是指在不打开或编辑文件的情况下&#xff0c;通过某种方式查看文件的内容、格式或者部分内容的功能。该功能通常用于文件管理系统、办公工具、在线教育平台、企业协作平台、电子邮件客户端等领域&#xff0c;能…

Android笔记(三十七):封装一个RecyclerView Item曝光工具——用于埋点上报

背景 项目中首页列表页需要统计每个item的曝光情况&#xff0c;给产品运营提供数据报表分析用户行为&#xff0c;于是封装了一个通用的列表Item曝光工具&#xff0c;方便曝光埋点上报 源码分析 核心就是监听RecyclerView的滚动&#xff0c;在滚动状态为SCROLL_STATE_IDLE的时…