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
相关产品推荐
相关产品推荐

