You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Error Boundary栈追踪行号与实际文件不符的解决求助

问题:React Error Boundary显示转译后行号而非实际行号的解决办法

问题描述

错误在App.tsx第13行抛出,但Error Boundary展示的栈追踪显示为第35行(转译后的行号)。已知控制台中error.stack能正确显示实际行号(证明Source Map正常工作),但errorInfo.componentStack显示的是转译后的行号,如何让Error Boundary展示实际文件的行号?

错误截图

App.tsx 代码

import ErrorBoundary from "./ErrorBoundary";

function App() {
  return (
    <div>
      <ErrorBoundary>
        <Inner />
      </ErrorBoundary>
    </div>
  );
}

function Inner() {
  throw new Error("Error: I crashed!");
  return "App";
}

export default App;

ErrorBoundary.tsx 代码

import React from "react";

interface Props {
  children: React.ReactNode;
}
interface State {
  error: any;
  errorInfo: any;
}

const defaultState: State = {
  error: null,
  errorInfo: null,
};

class ErrorBoundary extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = defaultState;
  }

  componentDidCatch(error: Error, errorInfo: { componentStack: string }) {
    console.log("ErrorBoundary", { error, errorInfo });
    console.log(error instanceof Error);
    this.setState({
      error: error,
      errorInfo: errorInfo,
    });
  }

  render() {
    const fallback = (
      <div>
        <section>
          <h3>发生错误</h3>
          <h4>错误信息</h4>
          <pre>{this.state?.error?.message}</pre>
          <h4>error.stack</h4>
          <pre>{this.state?.error?.stack}</pre>
          <h4>errorInfo.componentStack</h4>
          <pre>{this.state?.errorInfo?.componentStack}</pre>
        </section>
        <button
          onClick={() => {
            this.setState(defaultState);
          }}
        >
          重试
        </button>
      </div>
    );

    if (this.state?.error?.message) {
      return fallback;
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

补充说明

控制台前两条日志显示正确行号(13行),说明Source Map正常工作,但第三条日志(errorInfo.componentStack)显示35行,这也是ErrorBoundary中展示的内容。

控制台截图

项目由npm create vite创建,项目结构如下:

项目结构截图


解决办法

问题核心是errorInfo.componentStack由React基于转译后的代码生成,不会自动通过Source Map映射到原始行号;而error.stack已经被浏览器自动解析映射。以下是几种可行方案:

1. 直接用error.stack替代展示

这是最简单的方案,直接在ErrorBoundary的 fallback 中展示error.stack,它已经包含了映射后的原始行号。修改render里的fallback部分:

<section>
  <h3>发生错误</h3>
  <h4>错误信息</h4>
  <pre>{this.state?.error?.message}</pre>
  <h4>错误栈(原始行号)</h4>
  <pre>{this.state?.error?.stack}</pre>
  {/* 可选择保留componentStack用于对比,或直接移除 */}
  <h4>组件栈(转译后行号)</h4>
  <pre>{this.state?.errorInfo?.componentStack}</pre>
</section>

2. 手动解析组件栈到原始行号(进阶)

如果需要保留React组件层级结构的栈信息,同时映射到原始行号,可以使用stacktrace-js库处理:

  • 安装依赖:
npm install stacktrace-js
  • 修改ErrorBoundary的componentDidCatch方法,解析并映射栈信息:
import StackTrace from 'stacktrace-js';

// ...

componentDidCatch(error: Error, errorInfo: { componentStack: string }) {
  StackTrace.fromError(error)
    .then(stackFrames => {
      const mappedStack = stackFrames.map(frame => 
        `${frame.functionName || '匿名函数'} at ${frame.fileName}:${frame.lineNumber}:${frame.columnNumber}`
      ).join('\n');
      this.setState({
        error: error,
        errorInfo: {
          ...errorInfo,
          mappedComponentStack: mappedStack
        }
      });
    });
}
  • 在fallback中新增展示映射后的栈:
<h4>映射后的组件栈</h4>
<pre>{this.state?.errorInfo?.mappedComponentStack}</pre>

3. 确保Vite的Source Map配置正确

检查项目根目录的vite.config.ts,确认Source Map已启用(开发环境默认启用,生产环境需手动开启):

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  build: {
    sourcemap: true, // 生产环境启用Source Map需权衡源码暴露风险
  },
});

内容的提问来源于stack exchange,提问作者pyjamas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 00:07:06