Wrong line numbers in component stack trace [TS + React]
Asked Answered
D

1

7

Problem

I'm adding an error boundary to my client-side React app. In development, I want to display the error with a stack trace in the browser window, similar to create-react-app's or nextjs's error overlays. Using webpack's devtool option, I'm able to generate a stack trace with the correct filename, but the wrong line number.

// This is what renders in the browser window
Error: You got an error!
    at ProjectPage (webpack-internal:///./src/pages/ProjectPage.tsx:96:11) // <-- 96 is the wrong line

// This is what shows up in the console
Uncaught Error: You got an error!
    at ProjectPage (ProjectPage.tsx?8371:128) // <-- 128 is the correct line

What I've tried

  • This answer suggests different devtool settings, but none of the ones I've tried provide correct line numbers.
  • This answer suggests changing the retainLines babel setting in webpack, but I'm not using babel to transpile my code, I'm using ts-loader. Also, the babel docs suggest this option is a workaround for people not using source maps, which shouldn't be an issue here.
  • This answer suggests an external library to parse the stack trace. I tried it, but it simply parses the existing trace into objects and the line numbers are still wrong.
  • The React docs suggest using babel-plugin-transform-react-jsx-source but again, I'm not using babel to transpile my code. Should I be?

I'm not sure if this is a problem with ts-loader, webpack, or some other fundamental step I'm not understanding about source mapping. Setting a debugger in componentDidCatch and inspecting the error gives me the wrong line number, but when it gets logged to the console it's correct. It seems that the console has an additional step to map the correct line numbers; is this something I need to do manually?

ErrorBoundary.tsx

class ErrorBoundary extends React.Component {
  state = {
    error: null,
  };

  static getDerivedStateFromError(error) {
    return {
      error,
    };
  }

  componentDidCatch(error, errorInfo) {
    // Line numbers are wrong when inspecting in the function, but correct when logged to the console.
    console.log(error, errorInfo);
  }

  render() {
    return this.state.error ?
      <ErrorPage error={this.state.error} /> :
      this.props.children;
  }
}

ErrorPage.tsx

const ErrorPage = ({ error }) => {
  if (__DEV__) {    
    return (
      <Layout title={error.name}>
        <h1>{error.name}: {error.message}</h1>
        <pre>{error.stack}</pre>
      </Layout>
    );
  }

  // Display a nicer page in production.
};

tsconfig.json

{
  "compilerOptions": {
    "allowJs": true,
    "esModuleInterop": true,
    "jsx": "react",
    "lib": ["es2015", "dom"],
    "module": "commonjs",
    "sourceMap": true,
    "target": "es6"
  }
}

webpack.config.js

module.exports = (env, argv) => {    
  return {
    mode: isProduction ? 'production' : 'development',
    output: {
      path: path.join(__dirname, env.output_path),
      filename: 'app.bundle.js',
    },
    resolve: {
      extensions: ['.ts', '.tsx', '.js', '.jsx'],
    },
    devtool: isProduction ? 'source-map' : 'eval-source-map',
    entry: ['./src/index.tsx'],
    module: {
      rules: [
        {
          test: /\.ts(x?)$/,
          exclude: /node_modules/,
          loader: 'ts-loader',
        },
        ...
      ],
    },
    devServer: {
      contentBase: path.join(__dirname, env.output_path),
      disableHostCheck: true,
      historyApiFallback: true,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Headers': '*',
      },
    },
  };
};
Duke answered 11/8, 2020 at 20:19 Comment(4)
experiment w/ changing source map type in webpack configNochur
@frozen: Thanks, I've done that. I didn't exhaustively try every single one, but I did try all the ones that I had seen suggested. Is there one in particular you'd recommend?Duke
Any luck here? Having the same issuePremier
@tmm1: Didn't get it to work. I ended up using the error overlay plugin for webpack: npm.im/error-overlay-webpack-pluginDuke
D
5

I ended up using error-overlay-webpack-plugin to solve my problem. While it didn't solve the low-level issue in my question (why aren't the line numbers correct in the stack trace?), it did solve my meta-issue (display a nice stack trace in dev) in a much simpler way. Maybe others will find this solution useful as well:

// webpack.config.js

const ErrorOverlayPlugin = require('error-overlay-webpack-plugin');

const plugins = [
  ...
];

if (!isProduction) {
  plugins.push(new ErrorOverlayPlugin());
}

return {
  ...
  plugins,
};
Duke answered 16/9, 2020 at 18:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.