记录Sentry在微前端qiankun架构中的踩坑与解决方案

425 阅读2分钟

前言

众所周知,Sentry是一款实时的错误监控和性能监控工具,可以帮助开发者快速定位应用程序中的问题。

对于前端开发者而言,Sentry配合编译产物 source-map 可以精准地映射线上代码报错到源码位置。但是,不知道大家在使用qiankun时遇到过这个问题没有,子应用在发生报错后,通过 source-map 映射出的源码位置却完全不正确?

image.png

解决思路

调研Sentry的sdk发现,其提供了方法可以在上报信息前改变数据内容,如果能拿到正确的信息数据再上传即可解决问题。

那怎么拿到正确的信息呢?首先有一点是明确的,也是我写的解决方案的前提条件,编译打包后的js文件不管看起来多大,其本质是一行代码。那只要我能拿到正确的列数据就能解决这个问题了。

解决方案

  1. 在代码中注册sentry,打印sentry提供的报错信息,然后项目中进行事件抛错。

注册sentry

import * as Sentry from "@sentry/react";

Sentry.init({
  // dsn等相关配置
  beforeSend(event) {
    console.log(event)
    return event;
});

抛错代码:

    <div 
        style={{ display: 'none' }}
        onClick={() => { throw new Error('sentry test2'); }} 
    > 
        sentry2 
     </div>
  1. 在页面上触发报错。建议这里在本地跑项目拿到抛错的光标位置。

image.png

image.png

  1. 找到sentry抛错信息栈的最后一条数据

image.png

可以看到sentry给的colno是56909,这就是打包后的js中报错位置的列信息。

  1. 接下来用浏览器打开上面的filename文件,将文件内容全部拷贝到vscode中,然后全局搜索抛错文案并把光标放到步骤2中的位置,此时能看到报错真正的列信息。

image.png

  1. 计算偏移量,sentry给出的数据是56909,而通过js找到的数据是56265,偏移量是644。那我们在上传时做一个减法即可。
import * as Sentry from "@sentry/react";

Sentry.init({
  // dsn等相关配置
  beforeSend(event) {
     event.exception.values = event.exception.values.map((item: any) => {
      if (item.stacktrace) {
        const {
          stacktrace: { frames },
          ...rest
        } = item;

        frames[frames.length - 1].colno -= 644;
        return {
          ...rest,
          stacktrace: {
            frames,
          },
        };
      }
      return item;
    });
    return event;
  },
});

至此,问题得到了完美解决,我在不同的子应用甚至不同的微前端项目中反复论证,偏移量都是644。

image.png

总结

虽然解决了这个问题,但方法有点复杂,不知道是否有其他简单点方式。从最终结论猜测造成这个现象的原因,大概是因为子应用需要实现一些协议来连接Qiankun的主应用,所以打包时会注入一些代码,而且这多出来的代码量是固定的。